我正在学习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
Run Code Online (Sandbox Code Playgroud)
但是一旦我实例化对象我就会收到错误
!! AttributeError: 'c_asnbase.Context' object has no attribute 'msg'
这是否意味着一旦你用cdef定义一个python类,所有自我.*属性必须是cdef定义的?
这是否意味着一旦你用cdef定义一个python类,所有自我.*属性必须是cdef定义的?
cdef类中的属性与常规类中的属性的行为不同:
- 必须在编译时预先声明所有属性
- ...
通过将属性定义为object类型,您可以非常愉快地存储字符串:
cdef public object msg
Run Code Online (Sandbox Code Playgroud)
在内部,其原因是cdef class没有字典,这节省了空间并使属性访问更快,但它确实意味着它不能在运行时添加任意属性.这与__slots__在普通Python类中使用非常相似.
正如@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
Run Code Online (Sandbox Code Playgroud)
现在:
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
Run Code Online (Sandbox Code Playgroud)
注意:setattr(a,'new_attr', None)如果cdef class A没有定义是不可能的__dict__,而是有cdef public object question。
显然,使用 会产生额外的成本__dict__,因此每当性能很重要时,人们可能会使用预定义的属性。cdef-classes 的优点之一是较小的内存占用(例如因为没有__dict__-slot)。所以添加__dict__-slot 至少会抵消一些优势——人们应该问,另一种设计是否是更好的选择——但显然有一些场景,添加__dict__-slot 是有意义的。
另一种方法是创建 的子类cdef class并使用它而不是基类。
一旦__dict__槽被限定为,类的实例A有__dict__-attribute(其不是通常的情况下cdef-班)。但是, __dict__不包含cdef-attributes,例如answer来自上面的示例(无论它们是否公开)-仅包含普通的纯 python 属性(例如question和new_attr上面的示例中)。
这里以上面的例子为例:
# no answer-attribute in __dict__:
a.__dict__
# {'new_attr': None, 'question': 'Why?'}
Run Code Online (Sandbox Code Playgroud)
注意:这是Cython 文档中关于动态属性的部分。