Cython扩展类型支持类属性吗?
问题内容:
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
问题答案:
简短的答案是是和不是。
不,没有方便的语法惯用法可用于在中快速插入class属性cdef class
。但是..
整个问题cython
在于,它为您提供了较低级别的访问权限。付出额外努力的通常动机是表现,但您也可以C
通过额外的自由来做类似的事情。困难在于,存在许多陷阱,在这种情况下,如果python
不进行大量工作就不会获得纯类属性。但是,获得简单用例所需的东西非常容易。
例如,假设我将某个计算引擎作为一个类,并且希望为所有实例全局设置返回值的精度。我希望在编译时使用默认值,有时我可能希望将其调低以快速处理一些试验,然后为我的最终工作将其调高。类属性是按顺序制作的,但是您可以通过以下方式获得所需的功能cython
:
首先,在模块级别定义以下内容:
cdef int _precision[1] # storage for my class 'attribute'
_precision[0]=8 # my default value, set during compilation
使用数组允许我们使用与C等效的cython
惯用法。由于数据项是一个数组,因此该名称隐式是一个指针。这允许使用语法习语从存储位置转换为python引用。如果只需要一个全局常量,该常量可以由模块中任何类中的代码访问,则说明您已经完成。如果要严格将其用作类属性,则必须强制执行该规则-
编译器不在乎。precision[0]``*precision``cdef``precision``cython``cython``cdef
现在,如果您还想从python
代码中调整值,则需要使用模块cdef
中的python
代码可以调用的一对函数来访问“属性”:
cdef int* get_precision(): return _precision
cdef void* set_precision(int i): _precision[0]=i
此时python
,除非您真的想出汗,否则语义将与pure有所不同。您需要一个python
setter和getter函数,我发现python
用properties实现的描述符协议是最简单的:
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引用。第二个参数将“属性”设置为python
整数值,并规定要处于限制范围之内。该cython
函数调用和返回接口自动进行转换,这比他们看起来更复杂的照顾。
例如,get_precision
返回C-pointer
。如果您进行了取消引用,则get_precision
尝试返回in时会收到错误消息C-int
,__get__
就像返回python
。如果相反,您只是省略了[0]
取消引用,则在__get__
尝试返回a时会出现错误,C-pointer
就好像它是一个python int
。按照书面规定,自动转换可以正确匹配类型。
cython
对这种事情非常挑剔,并且可以静默返回不正确的值,这些值只能在运行时发现。可能需要做一些实验才能推断出正确的咒语。
该文档字符串告诉您不要期望纯python
类属性。如果您想对子类进行分类,并且让子类使用其他全局设置,则需要多花点功夫。在中python
,所有这些操作都是自动完成的。
即使这样,仍然存在其他差异。可以在类或实例上引用真实的类属性。此属性只能在实例上引用。在实例上设置真实的类属性会创建一个实例特定的副本,而类属性保持不变,但对更改后的实例不可见。
对于给定的用例,这可行。真正的类属性是不必要的。由于cython
代码通常不是那么抽象,而且计算量很大,因此这种最小的方法通常就足够了。