【问题标题】:Python extension type: super() not finding method (a.k.a. attribute) in base classPython 扩展类型:super() 在基类中找不到方法(又名属性)
【发布时间】:2015-01-06 01:25:42
【问题描述】:

我正在重新编码 PyCXX,它是 Python 的 C++ 包装器。

将方法添加到新样式类的原始(工作)实现涉及为每个方法创建一个“extern C”处理程序函数,使用指向这些处理程序的指针填充 PyMethodDef 表,并将 PyTypeObject 的 table->tp_methods 放置到此表中.

相反,我用覆盖 getattro 的机制替换了该机制,搜索我自己的数据以查看此属性是否具有相应的 C++ 方法,如果有,则将其打包到可调用 Python 对象中并返回它,否则遵循 PyObject_GenericGetAttr。

如果我创建一个 new_style_class 的实例,这种技术就可以工作:

# new_style_class is a C++ class deriving from ExtObj_new
_new_style_class = simple.new_style_class()
_new_style_class.func_noargs()

但是,如果我尝试从新样式类派生并从基类调用 func_noargs(),如下所示:

print( '--- Derived func ---' )
class Derived(simple.new_style_class):
    def __init__( self ):
        simple.new_style_class.__init__( self )

    def derived_func( self ):
        print( 'derived_func' )
        print( vars(super()) )
        super().func_noargs() # <-- AttributeError: 'super' object has no attribute 'func_noargs'

d = Derived()
d.derived_func()

... 它返回 AttributeError: 'super' object has no attribute 'func_noargs'。

我想知道问题是否来自我正在覆盖 getattro 而不是 getattr 的事实。

CPython 是否有可能在尝试调用基本属性时直接查看 base.getattr 而完全错过了 base.getattro?

如果是这样?这算不算错误?

【问题讨论】:

  • 请告诉我们声明func_noargs()的确切代码。如果它只是一个碰巧可调用的实例属性,super() 可能找不到它。换句话说,如果您希望 super() 工作,此代码必须工作:simple.new_style_class.func_noargs(instance)

标签: python derived-class base-class getattr


【解决方案1】:

参考文献

tp_getattr 已被弃用,因此tp_getattro 将是更好的选择。但这根本不是正确的方法。查看 Python 的Objects/typeobject.c 源文件,你会发现super 类型的定义,以及一个静态函数add_methods,它定义了一个类型的方法。这三个一起说明了为什么会遇到问题。

为什么不使用tp_getattro“定义”方法

通常将此字段设置为PyObject_GenericGetAttr()比较方便,实现了查找对象属性的正常方式。

所以查找只为对象定义而不为类型定义,但方法应该为类型定义。

方法是如何定义的

函数add_methods 迭代tp_methods,用PyDescr_NewMethod 定义每个方法(PyCFunction_New 用于静态方法)并将其添加到类型对象的字典中。

super 如何搜索方法

超类型定义tp_getattro。现在super().func_noargs() 将触发在超级对象中查找func_noargs。这意味着,func_noargs 将在每个相关超类型的字典中查找。如果没有找到,__class__ 被请求或super 的第二个参数未定义或None,超级对象将调用自己的PyObject_GenericGetAttr。所以你的tp_getattro 永远不会被调用。

结论

如果你不喜欢你原来的(工作的)解决方案,你应该把你在tp_getattro 中返回的函数放入类型对象的字典中。

【讨论】:

    猜你喜欢
    • 2018-07-12
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    相关资源
    最近更新 更多