You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cython扩展类__getattr__与Python类行为不一致,触发递归循环

解决Cython扩展类中__getattr__的递归循环问题

这个问题我之前也碰到过,核心是Cython的cdef class和普通Python类对__dict__的处理逻辑完全不同,导致你在__getattr__里访问self.__dict__时触发了无限递归。

为什么会出现递归?

在普通Python类中,每个实例默认自带__dict__用来存储动态属性,所以访问self.__dict__不会触发__getattr__——__getattr__只有在访问不存在的属性时才会被调用。

但Cython的cdef class不一样:为了性能优化,默认情况下不会自动创建__dict__。当你在__getattr__里尝试访问self.__dict__时,因为这个属性根本不存在,Cython会再次调用__getattr__来查找__dict__,于是就形成了无限递归循环。

两种可行的解决方案

方案1:给cdef类显式添加__dict__支持

如果你确实需要用__dict__存储动态属性,可以在类定义里声明并初始化__dict__,这样它就会变成类的cdef属性,访问时不会触发__getattr__:

cdef class mockClass:
    cdef int _val
    cdef dict __dict__  # 显式声明__dict__属性
    def __init__(self, val):
        self._val = val
        self.__dict__ = {}  # 初始化__dict__为空字典
    def __getattr__(self, attrName):
        print('Getattr:', attrName)
        print('This works in cython:', self.__dict__)
        try:
            return self.__dict__[attrName]
        except KeyError:
            raise AttributeError(f"Unknown attribute: {attrName}")
    def __add__(self, val):
        return mockClass(self._val + val)
    def __str__(self):
        return str(self._val)

方案2:绕过__getattr__直接获取属性

如果你不需要__dict__,只是想安全地获取实例属性,可以使用object.__getattribute__跳过__getattr__的触发,直接访问属性:

cdef class mockClass:
    cdef int _val
    def __init__(self, val):
        self._val = val
    def __getattr__(self, attrName):
        print('Getattr:', attrName)
        try:
            # 使用object的内置方法绕过__getattr__,直接查找属性
            return object.__getattribute__(self, attrName)
        except AttributeError:
            raise AttributeError(f"Unknown attribute: {attrName}")
    def __add__(self, val):
        return mockClass(self._val + val)
    def __str__(self):
        return str(self._val)

额外注意点

  • Cython的cdef属性(比如你的_val)是直接内存访问的,不会触发__getattr__,只有访问未在cdef中声明的Python属性时,才会触发__getattr__。
  • 如果你不需要动态添加属性,尽量不要给cdef类添加__dict__,会损失Cython的性能优势。

内容的提问来源于stack exchange,提问作者mqnguyen1988

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 21:19:06