Python扩展类型:super()在基类中没有查找方法(a.k.a.属性)

时间:2014-11-09 18:53:47

标签: python derived-class base-class getattr

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

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

相反,我用覆盖getattro的机制替换机制,搜索我自己的数据以查看此属性是否具有相应的C ++方法,如果是,则将其打包到Callable 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'对象没有属性'func_noargs'。

我想知道这个问题是否来自于我压倒getattro而不是getattr。

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

如果是这样的话?这有资格作为错误吗?

1 个答案:

答案 0 :(得分:2)

参考

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

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

  

将此字段设置为PyObject_GenericGetAttr()通常很方便,它实现了查找对象属性的常规方法。

因此,只为对象而不是类型定义查找,但应为类型定义方法。

如何定义方法

函数add_methods遍历tp_methods,使用PyDescr_NewMethodPyCFunction_New定义静态方法的每个方法)并将其添加到类型对象的字典中。

super如何搜索方法

超级类型定义tp_getattro。现在super().func_noargs()将触发超级对象中func_noargs的查找。这意味着,func_noargs将在每个相关超类型的字典中查找。如果未找到任何内容,则请求__class__或未定义super的第二个参数或None,超级对象将自行调用PyObject_GenericGetAttr。因此,您的tp_getattro永远不会被调用。

结论

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