我正在重新编码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?
如果是这样的话?这有资格作为错误吗?
答案 0 :(得分:2)
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
中返回的函数放入类型对象的字典中。