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

为何len(obj)不经过__getattribute__,如何覆盖该行为?

为何len(obj)不经过__getattribute__,如何覆盖该行为?

首先得搞明白为什么len(obj)会绕过__getattribute__:这是CPython解释器为了性能做的针对性优化。像len()、dir()这种高频使用的内置函数,根本不会走实例的__getattribute__属性查找流程,而是直接从对象所属类的底层结构(比如类型对象的方法槽位)里获取对应的特殊方法(比如__len__)。毕竟这些是Python的基础操作,跳过属性查找能大幅提升执行效率。

看你给出的例子,obj.__len__()是明明白白从实例上获取__len__属性,所以必然会触发__getattribute__;但len(obj)是调用内置函数,解释器会直接去类的方法表中找__len__,完全绕开了实例层面的__getattribute__拦截。

那有没有办法让len(obj)强制走__getattribute__("__len__")呢?在标准CPython里,没有官方原生的方式能直接修改这个内置逻辑——因为这是硬编码在解释器核心里的。不过我们可以用点小技巧,让len(obj)间接触发__getattribute__。

可行方案:在__len__里手动触发__getattribute__

我们可以把类的__len__做成一个“中转方法”,让它主动调用__getattribute__来获取真正的长度计算逻辑。这样当len(obj)调用__len__时,就会顺带着触发__getattribute__。

修改你的示例代码如下:

class Custom:
    def __getattribute__(self, item):
        print(f"Accessing: {item}")
        # 这里可以根据需求动态返回__len__的实现
        if item == "__len__":
            def dynamic_len():
                return 50
            return dynamic_len
        return super().__getattribute__(item)
    
    def __len__(self):
        # 主动通过__getattribute__获取长度计算逻辑
        return self.__getattribute__("__len__")()

obj = Custom()

print(obj.__len__())  # 正常触发__getattribute__
print(len(obj))       # 现在也会触发__getattribute__

运行输出:

Accessing: __len__
50
Accessing: __len__
50

这个思路的核心是把len(obj)的调用链路,通过类的__len__中转,引到__getattribute__上。如果要对其他内置函数(比如dir()、repr())做同样的处理,只需要给对应的特殊方法(__dir__、__repr__)也加上类似的中转逻辑就行。

注意事项

这种方式只是模拟了你想要的效果,并没有真正改变内置函数的底层行为。解释器还是会直接查找类的特殊方法,只是我们在这个方法里手动加入了__getattribute__的调用。

另外,别想着用元类、描述器去拦截类层面的方法查找——内置函数的逻辑是直接和类型对象的底层槽位交互,完全绕开了常规的属性查找流程,这些手段根本碰不到它。


备注:内容来源于stack exchange,提问作者Ziv Sion

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 19:33:13