在cdef类中混合使用cdef和常规python属性

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在cdef类中混合使用cdef和常规python属性相关的知识,希望对你有一定的参考价值。

我正在学习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类,所有自我。*属性必须是cdef定义的?

答案

这是否意味着一旦你用cdef定义一个python类,所有自我。*属性必须是cdef定义的?

是。这在the documentation中明确说明:

cdef类中的属性与常规类中的属性的行为不同:

  • 必须在编译时预先声明所有属性
  • ...

通过将属性定义为object类型,您可以非常愉快地存储字符串:

cdef public object msg

在内部,原因是cdef class没有字典,这节省了空间并使属性访问更快,但它确实意味着它不能在运行时添加任意属性。这与在普通Python类中使用__slots__相似。

另一答案

正如@DavidW指出的那样,cdef-class的问题在于它们没有__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的子类并使用它而不是基类。


注意:关于动态属性的Cython文档中的here is the part

以上是关于在cdef类中混合使用cdef和常规python属性的主要内容,如果未能解决你的问题,请参考以下文章

电脑cdef盘各是干啥的

如何在 cdef 中等待?

如何在本机回调中使用 Cython cdef 类成员方法

Code::Blocks C++ 使用 MacOS Mojave 编译:致命错误:sys/cdefs.h:没有这样的文件或目录

Cython 一篇通

为什么__setitem__比cdef-classes的等效“普通”方法快得多?