如何在Cython中实现让Python解释器‘遗忘’类实例?
Cython类实例的"自我销毁"实现问题
定义的Cython类
cdef class MyClass: cdef readonly object _value def __cinit__(self, value): self._value = value cpdef forget_self(self): # 此处应编写什么代码?
期望的Python行为
>>> my_class = MyClass(5) >>> my_class._value 5 >>> my_class.forget_self() >>> my_class # 此处触发NameError
疑问与需求
我知道_Py_ForgetReference这个函数,但它仅在开启Py_TRACE_REFS宏时才可用。如果没办法触发NameError,我希望forget_self()能把当前实例设为None,想问问Py_SETREF能不能实现这个需求?
解答
关于触发NameError的可能性
你想要的触发NameError的行为根本做不到——my_class是Python作用域里的变量,它只是指向Cython实例的一个引用。实例的方法没办法直接修改外部变量的引用关系,更没法让变量名从作用域里消失,NameError只会在变量名不存在时触发,这不是实例能控制的。
关于Py_SETREF的作用
Py_SETREF的功能是安全替换Python对象指针:它会先对旧对象做引用计数减一,再赋值新对象,还能处理空指针的情况。但它没法把外部的my_class变量设为None——self是方法内部的局部指针,修改self的指向(比如Py_SETREF(&self, NULL))只会改变方法内的局部变量,对外部的my_class变量完全没影响。
可行的替代方案
如果想让实例本身失去可用性,可以给实例加一个失效标记,同时清空内部引用:
cdef class MyClass: cdef readonly object _value cdef bint _valid def __cinit__(self, value): self._value = value self._valid = True cpdef forget_self(self): # 清空内部引用,减少引用计数 Py_CLEAR(self._value) self._valid = False def __getattr__(self, name): if not self._valid: raise ValueError("该实例已失效") raise AttributeError(f"没有属性 '{name}'")
调用forget_self()后,实例虽然还被my_class变量引用,但访问任何属性都会抛出错误,达到类似"销毁"的效果。
另外补充:_Py_ForgetReference确实只在调试模式(开启Py_TRACE_REFS)下存在,不能用于生产代码,它是用来手动从引用追踪链表移除对象的,正常场景下Python的GC会自动处理引用计数。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

