Cython cdef类@property方法内访问其他@property返回0值问题
问题原因
核心问题出在cdef class的C属性声明逻辑:你在类开头写了cdef double distance, miles, meters, km,直接为类定义了4个C级别的实例属性,其中km、miles、meters和你后续用@property定义的属性完全重名。
Cython编译cdef类时的属性访问规则是:
- 类内部的Cython代码访问
self.xxx时,如果存在同名的C层属性,会直接通过内存偏移读取C属性值,完全不走Python的属性查找逻辑,也就不会触发你定义的@property描述符方法 - cdef声明的C属性默认是私有状态,外部Python代码无法直接访问,因此外部访问同名属性时,会自动 fallback 到类上定义的
@property方法
这就解释了你看到的所有现象:
__cinit__方法中你只给self.distance赋值了42.0,其余三个C属性miles、meters、km都是double类型,实例化时默认初始值为0.0- 在
miles、meters属性方法内部写self.km时,Cython直接读取C层km属性的初始值0.0,根本没有调用你写的km属性方法,因此打印值为0,计算结果也为0 - 外部IPython环境中访问
Distance(42).km时,因为访问不到C层私有km属性,就触发了你定义的kmproperty,返回self.distance的42.0,结果看似正常。
修复方案
删掉cdef声明中与property重名的C属性即可,只保留实际需要存储原生值的C属性:
import cython cdef double MILES_PER_KILOMETER = 0.621371 cdef class Distance: # 仅保留实际存储值的C属性,移除miles、meters、km的C层声明 cdef double distance def __cinit__(self, double distance) -> None: self.distance = distance @property def miles(self): print(self.km) return self.km * MILES_PER_KILOMETER @property def meters(self): print(self.km) return self.km * 1000.0 @property def km(self): return self.distance
修改后类内部访问self.km时因为不存在同名C属性,就会正常触发km的property方法,返回正确的计算结果。
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

