Cython扩展类型是否支持类属性?

Pwn*_*rus 10 c python types class cython

Python类可以具有类属性:

class Foo(object):
   bar = 4
Run Code Online (Sandbox Code Playgroud)

是否有类似的结构用于在Cython扩展类型中定义类属性?例如,当我尝试编译以下cython代码时

cdef class Foo:
    cdef int bar
    bar = 4
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

thing.c:773:3: error: use of undeclared identifier 'bar'
  bar = 4;
  ^
1 error generated.
error: command 'cc' failed with exit status 1
Run Code Online (Sandbox Code Playgroud)

小智 9

简短的回答是肯定的和否定的。

不,没有一个方便的语法习惯用法可以在cdef class. 然而 ....

重点cython是它为您提供了较低级别的访问权限。额外努力的通常动机是表现,但你也可以做C类似的事情,拥有额外的自由。困难在于,有很多陷阱,在这种情况下,如果python没有大量工作,您将无法获得纯类属性。尽管如此,很容易获得简单用例所需的东西。

例如,假设我正在制作一些计算引擎作为一个类,并且我希望全局设置所有实例的返回值的精度。我希望在编译时有一个默认值,有时我可能想将它调低以快速处理一些试验,然后在我的最终工作中将其调高。类属性是定制的,但您可以获得所需的功能cython,如下所示:

首先,在模块级别定义以下内容:

cdef int _precision[1]  # storage for my class 'attribute'
_precision[0]=8         # my default value, set during compilation
Run Code Online (Sandbox Code Playgroud)

使用数组允许我们使用与 C 等效的cython习惯用法。由于数据项是一个数组,因此名称隐含地是一个指针。这允许使用句法习语从存储位置转换为 python 引用。如果你想要的只是一个全局常量,它可以被模块中任何类中的代码访问,那么你就完成了。如果您想严格地将它用作类属性,则必须强制执行该规则 - 编译器不在乎。precision[0]*precisioncdefprecisioncythoncythoncdef

现在,如果您还想从python代码中调整值,您将需要一对cdef函数,python模块中的代码可以调用这些函数来访问“属性”:

cdef int*  get_precision(): return _precision
cdef void* set_precision(int i): _precision[0]=i
Run Code Online (Sandbox Code Playgroud)

在这一点上,语义会与 pure 有所不同python,除非您真的想出汗。你需要一个pythonsetter 和 getter 函数,我发现python由属性实现的描述符协议是最简单的:

cdef class SomeCalculator:
  ...

  property precision:
    def __get__(self):
      """Get or set calculation precision, default == 8.
         This is like a class attribute: setting affects all instances,
         however, it also affects all subclasses."""
      return get_precision()[0]
    def __set__(self,int integer): set_precision(min(30,max(0,integer)))
Run Code Online (Sandbox Code Playgroud)

第一个获取对“属性”的python 引用。第二个设置具有python整数值的“属性” ,监管在限制范围内。该cython函数调用和返回接口自动进行转换,这比他们看起来更复杂的照顾。

例如,get_precision返回一个C-pointer. 如果您在 in 中进行了取消引用,则get_precision尝试返回in时会出错C-int__get__就好像它是python. 相反,如果您只是省略了[0]取消引用,__get__则会在尝试返回 a 时出错,C-pointer就好像它是 a 一样python int。正如所写,自动转换正确匹配类型。 cython对这类事情非常挑剔,并且可以默默地返回不正确的值,只有在运行时才能发现。推断正确的咒语可能需要一些实验。

文档字符串告诉您不要期望纯python类属性。如果你想要子类,并且让子类使用不同的全局设置,你需要多费点力气。在 中python,所有这些都是自动完成的。

即便如此,还有其他差异。可以在类或实例上引用真正的类属性。此属性只能在实例上引用。在实例上设置真正的类属性会创建一个特定于实例的副本,使类属性保持不变,但对更改的实例不可见。

对于给定的用例,这是有效的。真正的类属性是不必要的。由于cython代码通常不那么抽象且计算密集,因此这种最小的方法通常就足够了。


mic*_*tux 6

虽然似乎不可能有C类型的静态属性,但Cython扩展类型可以具有常规的Python静态属性,这些属性也可以在Python中自动访问.只需声明它们就像在Python中声明它们一样:

cdef class Foo:
    bar = 4
Run Code Online (Sandbox Code Playgroud)

生成的代码显示这些静态属性作为Python对象存储在类对象的属性dict中,即如果在使用C类型的上下文中使用它们,则它们将从Python对象转换回来.

  • 似乎这些是只读的。有没有办法使 Cython 扩展中的类属性可公开访问? (2认同)