我正在学习Cython,现在正在尝试它。我尝试了基本的cdef类示例程序,它运行得很好。
现在我要做的是在cdef类类型中混合使用cdef和非cdef属性,类似这样
cdef class Context:
cdef public int byteIndex, bitIndex
def __init__(self, msg = "", msg_len = 0):
self.msg = msg
self.msg_len = msg_len
self.byteIndex = 0
self.bitIndex = 7
但是只要我实例化对象我就会收到错误
!! AttributeError: 'c_asnbase.Context' object has no attribute 'msg'
这是否意味着一旦你用cdef定义了一个python类,所有self。*属性必须是cdef定义的?
答案 0 :(得分:7)
这是否意味着一旦你用cdef定义了一个python类,所有self。*属性必须是cdef定义的?
是。这在the documentation中明确说明:
cdef类中的属性与常规类中的属性的行为不同:
- 所有属性必须在编译时预先声明
- ...
通过将属性定义为object类型,您可以非常愉快地存储字符串:
cdef public object msg
在内部,原因是cdef class
没有字典,这节省了空间并使属性访问更快,但它确实意味着它不能在运行时添加任意属性。这与在普通Python类中使用__slots__
非常相似。
答案 1 :(得分:0)
正如@DavidW所指出的,cdef类的问题是它们没有__dict__
。如果确实需要,可以将__dict__
添加到类定义中:
%%cython
cdef class A:
cdef dict __dict__ # now the usual attribute look-up is possible
cdef readonly int answer
def __init__(self):
self.answer=42 #cdef attribute
self.question="unknown" #pure python attribute, possible
现在:
a=A()
print(a.answer)
# 42
print(a.question)
# 'unknown'
a.question = 'Why?'
print(a.question)
# 'Why?'
setattr(a,'new_attr', None)
print(a.new_attr)
# None
注意:如果setattr(a,'new_attr', None)
的定义中没有cdef class A
,而是__dict__
,则cdef public object question
是不可能的。
使用__dict__
显然会带来额外的成本,因此只要性能重要,人们就可能会使用预定义的属性。
另一种方法是创建cdef class
的子类并使用它而不是基类。
NB:有关动态属性的Cython文档中的here is the part。