只要在类中定义__call__方法,该类的实例就能像函数一样被调用;它是Python可调用协议的实现,解释器执行obj()时自动触发__call__,支持状态保持,适用于需跨调用维护上下文的场景。

直接说结论:只要在类中定义 __call__ 方法,该类的实例就能像函数一样被调用;它不是“转换”,而是让实例具备调用行为——本质是 Python 对可调用协议(callable() 返回 True)的实现。
为什么定义了 __call__ 就能被调用?
Python 在执行 obj() 时,会检查 obj 是否有 __call__ 方法。如果有,就自动触发它,传入括号里的参数;没有则抛出 TypeError: 'X' object is not callable。
这和 __len__、__str__ 类似,属于特殊方法(dunder method),由解释器隐式调用。
-
__call__必须是实例方法(第一个参数通常是self) - 它可接收任意参数(
*args、**kwargs),返回值无限制 - 类本身仍是类,实例仍是实例,只是多了“被调用”的能力
__call__ 和普通方法、闭包、functools.partial 的区别在哪?
关键在于状态保持和复用方式:
- 普通方法必须显式写
obj.method(),不能省略方法名 - 闭包(如
lambda或嵌套函数)无法直接绑定实例属性,除非手动捕获,且每次生成新对象 -
functools.partial是固定部分参数的函数包装,不带内部状态 -
__call__实例天然持有self,可读写属性(比如计数器、缓存、配置),适合需要“有记忆的调用”场景
示例:一个带调用次数统计的加法器
class Adder:
def __init__(self, offset=0):
self.offset = offset
self.count = 0
<pre class="brush:php;toolbar:false;">def __call__(self, x, y):
self.count += 1
return x + y + self.offsetadd5 = Adder(offset=5) print(add5(2, 3)) # → 10(2+3+5) print(add5(1, 1)) # → 7(1+1+5) print(add5.count) # → 2
常见错误和容易忽略的细节
实际写的时候,这几个点最容易翻车:
- 忘了
self参数:写成def __call__(x, y):会导致TypeError: __call__() missing 1 required positional argument: 'y'(因为self被当成第一个实参传进去了) - 误以为
__call__影响类的初始化:它和__init__完全无关,__init__只在MyClass()实例化时运行一次 - 在装饰器中滥用:如果用类做装饰器,
__call__会被用于包装目标函数,但要注意是否要支持带参数的装饰语法(此时需两层嵌套) - 性能上无额外开销:调用
obj()和调用obj.__call__()几乎等价,但前者更符合直觉,也支持 IDE 自动补全
真正复杂的地方不在语法,而在于想清楚:这个“可调用对象”是否真的需要维护状态?如果只是临时封装逻辑,一个函数或 lambda 更轻量;一旦涉及跨多次调用的上下文(比如连接池、重试策略、配置快照),__call__ 才体现出不可替代性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











