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

Python中setattr设置对象__call__方法无效的原因及解决方法

为什么obj()和obj.call()在setattr后不等价?如何运行时设置__call__方法?

先看你给出的测试代码:

class A:
    def __call__(self):
        return 1

a = A()
print(a())          # 输出1
print(a.__call__()) # 输出1

setattr(a, '__call__', lambda: 100)
print(a())          # 还是输出1
print(a.__call__()) # 输出100

原因分析

Python里的特殊方法(双下划线包裹的方法,比如__call__、init),调用时是直接从实例的类(或类的继承链)中查找,不会去实例自身的属性字典里找。

当你写a()时,Python实际执行的逻辑是type(a).__call__(a)——也就是去A类里找__call__方法,完全不看实例a自身的__call__属性。
但当你直接写a.__call__()时,Python会先在实例a的属性里找__call__,找到了你用setattr设置的lambda,所以执行的是这个新函数。

这就是两者结果不一致的核心原因。

解决方法:运行时设置实例的__call__方法

要让a()调用新的逻辑,你需要修改实例所属类的__call__方法,或者给这个实例单独创建一个动态类:

方法1:修改原类的__call__

直接修改A类的__call__,这样所有A的实例都会受影响:

class A:
    def __call__(self):
        return 1

a = A()
A.__call__ = lambda self: 100  # 修改类的__call__
print(a()) # 输出100

方法2:给单个实例创建动态子类

如果只想让某个实例生效,不影响其他实例,可以给该实例动态生成一个子类,替换它的__class__属性:

import types

class A:
    def __call__(self):
        return 1

a = A()
# 创建一个继承自A的动态子类,重写__call__
DynamicClass = types.new_class('DynamicA', (A,), {}, lambda ns: ns.update({'__call__': lambda self: 100}))
a.__class__ = DynamicClass

print(a()) # 输出100

或者更简单的写法:

class A:
    def __call__(self):
        return 1

a = A()
# 临时子类
class TempA(A):
    def __call__(self):
        return 100

a.__class__ = TempA
print(a()) # 输出100

这样修改后,a()就会执行新的__call__逻辑,和a.__call__()的结果一致了。

内容的提问来源于stack exchange,提问作者Денис Швецов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:23:28