Python类可以有类属性:
class Foo(object):
bar = 4
是否有类似的结构用于在Cython扩展类型中定义类属性?例如,当我尝试编译以下cython代码时
cdef class Foo:
cdef int bar
bar = 4
我收到此错误:
thing.c:773:3: error: use of undeclared identifier 'bar'
bar = 4;
^
1 error generated.
error: command 'cc' failed with exit status 1
答案 0 :(得分:6)
虽然似乎不可能有C类型的静态属性,但Cython扩展类型可以有常规的Python静态属性,这些属性也可以在Python中自动访问。只需声明它们就像在Python中声明它们一样:
cdef class Foo:
bar = 4
生成的代码显示这些静态属性作为Python对象存储在类对象的属性dict中,即如果在使用C类型的上下文中使用它们,则它们将从Python对象转换回来。
答案 1 :(得分:4)
简短的回答是肯定的,不是。
不,在cdef class
中快速插入类属性没有方便的语法习惯用法。但是....
cython
的重点在于它为您提供了较低级别的访问权限。额外努力的通常动机是表现,但你也可以做C
- 就像有额外自由的事情一样。困难在于,存在许多陷阱,在这种情况下,如果没有大量工作,您将无法获得纯python
类属性。尽管如此,很容易获得简单用例所需的内容。
例如,假设我将一些计算引擎作为一个类,我希望全局设置所有实例的返回值的精度。我希望在编译时出现默认值,并且有时我可能希望将其调低以快速处理某些试验,然后在我的最终工作中将其调高。 class属性是按顺序排列的,但您可以在cython
中获得所需的功能,如下所示:
首先,在模块级别定义以下内容:
cdef int _precision[1] # storage for my class 'attribute'
_precision[0]=8 # my default value, set during compilation
使用数组允许我们使用等同于C cython
的{{1}}成语precision[0]
。 *precision
名称cdef
隐含地是指针,因为数据项是数组。这允许使用precision
句法习语从cython
存储位置转换为python引用。如果你想要的只是一个全局常量,可以通过模块中任何类中的cython
代码访问,那么你就完成了。如果要将其严格用作类属性,则必须强制执行该规则 - 编译器并不关心。
现在,如果您还要调整cdef
代码中的值,则需要一对python
函数,模块中的cdef
代码可以调用这些函数来访问&#39 ;属性':
python
此时,语义将与纯cdef int* get_precision(): return _precision
cdef void* set_precision(int i): _precision[0]=i
略有不同,除非你真的想要出汗。你需要一个python
setter和getter函数,我发现属性实现的python
描述符协议是最简单的:
python
第一个获得对'属性的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)))
积分值,并且受到限制。 python
函数调用和返回接口会自动处理转换,这些转换比它们看起来更复杂。
例如,cython
会返回get_precision
。如果您在C-pointer
中进行了解除引用,那么尝试在get_precision
中返回C-int
时会出现错误,就好像它是__get__
一样。如果您只是在python
中省略了[0]
取消引用,则在尝试返回__get__
时会出现错误,就好像它是C-pointer
一样。如上所述,自动转换正确匹配类型。 python int
对这类事情非常挑剔,并且可以静默地返回不正确的值,只能在运行时发现。可以通过一些实验来推断出正确的咒语。
docstring告诉您不要期望纯cython
类属性。如果你想要子类,并让子类使用不同的全局设置,你需要多出一点点。在python
中,所有操作都会自动完成。
即便如此,还有其他差异。可以在类或实例上引用实类属性。此属性只能在实例上引用。在实例上设置真实的类属性会创建一个特定于实例的副本,使类属性保持不变,但对更改的实例不可见。
对于给定的用例,这是有效的。不需要真正的类属性。由于python
代码通常不那么抽象且计算密集,因此这种最小的方法通常就足够了。
答案 2 :(得分:3)
你不能这样做。我不知道是否支持静态属性,但是" normal"必须从方法访问,例如构造函数:
cdef class Foo:
cdef int bar
def __init__(self):
self.bar = 4