假设我有cdef class
:
cdef class MyClass:
# declare some cdef attributes here
cdef dict __dict__
def __cinit__(self, *args, **kwargs):
self.__dict__ = {}
# do some other init stuff
我通常希望能够向MyClass
个实例添加属性,因此我有一个__dict__
属性。
我还希望有一种方法可以在运行时关闭它。我尝试添加__setattr__
:
def __setattr__(self, attr, val):
if not _STRICT:
object.__setattr__(self, attr, val)
return
if hasattr(self, attr):
object.__setattr__(self, attr, val)
else:
raise ValueError(
"Cannot set attribute '" + attr + "' on " +
self.__class__.__name__ +
' because that attribute does not exist!'
)
其中_STRICT
是一个可以在运行时切换的变量。
这个技巧在纯python中运行得很好,但是使用扩展类型我收到了这个错误:
TypeError: can't apply this __setattr__ to MyClass object
docs似乎表示我应该能够制作自定义__setattr__
,但我似乎遇到了this更改,导致无法使用object.__setattr__
在内置类型上设置属性。我尝试使用super().__setattr__
,但错误的方式完全相同。
是否有其他方法可以设置我缺少的Cython扩展类型的属性,还是有其他方法可以做到这一点?
答案 0 :(得分:1)
好的,我通过直接调用C api超越了我referenced的块:
from cpython.object cimport PyObject_GenericSetAttr
...
cdef class MyClass:
...
def __setattr__(self, attr, val):
# in non-strict mode, we always update the attribute or
# add it to the instance even if it is not already present
if not _STRICT:
PyObject_GenericSetAttr(self, attr, val)
return
# If we got here, we are in strict mode, and we only
# allow attribute setting if the instance already has
# that attribute
if hasattr(self, attr):
PyObject_GenericSetAttr(self, attr, val)
else:
raise ValueError(
"Cannot set attribute '" + attr + "' on " +
self.__class__.__name__ +
' because that attribute does not exist!'
)
注意:我尝试解决此问题的方法之一就是按照评论中的建议更新__dict__
。这不起作用,因为cdef
属性未存储在实例__dict__
中。如果您使用__dict__[attr] = val
更新dict,它会很乐意将其添加到dict中,但如果使用getattr(instance, attr)
关键字声明attr,则cdef
将不会返回您的更新。