在 Python 中,__call__
是一个特殊方法,用于使得一个类的实例可以像函数一样被调用。当你在一个类中定义了 __call__
方法后,该实例对象就变成了可调用对象。调用时,会自动触发该方法。
1. call 方法详解
-
作用:
定义__call__
方法后,实例对象可以使用圆括号传入参数进行调用。调用时,Python 解释器会将该调用转发给实例对象的__call__
方法。
举例来说,如果有一个实例obj
,当你执行obj(arg1, arg2)
时,实际上执行的是obj.__call__(arg1, arg2)
。 -
使用场景:
- 封装行为:可以将对象的某些行为封装成一个“可调用”的接口。
- 装饰器:实现装饰器时,经常使用
__call__
方法。 - 函数对象:在某些场景下,希望对象表现得像函数,例如实现状态机、策略模式等。
-
定义方式:
你可以在类中定义__call__
方法,并根据需要传入任意参数。返回值则为调用结果。
2. 示例代码
下面是一个简单的示例,展示了如何定义和调用 __call__
方法:
class Adder:
def __init__(self, initial_value):
self.initial_value = initial_value
def __call__(self, x, y):
# 当调用对象时,将计算 initial_value + x + y
return self.initial_value + x + y
# 创建一个 Adder 对象
add_obj = Adder(10)
# 直接调用对象,就会触发 __call__ 方法
result = add_obj(5, 3) # 实际上调用的是 add_obj.__call__(5, 3)
print(result) # 输出 18,因为 10 + 5 + 3 = 18
在这个例子中:
Adder
类在构造函数__init__
中接收一个初始值initial_value
。- 定义了
__call__
方法,该方法接收两个参数x
和y
,返回它们与initial_value
的和。 - 创建对象
add_obj
后,通过add_obj(5, 3)
调用__call__
方法,从而得到结果 18。
3. 调用说明
如果一个类定义了 __call__
方法,那么调用方式非常简单:
-
实例调用:直接用实例名加上括号传入参数,例如:
result = instance(arg1, arg2, ...)
这会自动调用
instance.__call__(arg1, arg2, ...)
。 -
链式调用:你可以将可调用对象作为其他函数的返回值使用,或者将它们传递给其他需要函数作为参数的地方。
4. 注意事项
- 参数灵活性:你可以在
__call__
方法中定义任意数量的参数,甚至支持关键字参数和可变参数。 - 状态保存:对象在
__call__
方法内可以利用实例属性保存状态,这使得可调用对象不仅仅是无状态函数。
5. 高级用法示例
有时你希望对象在被调用时能根据内部状态做出不同响应,比如实现带有缓存、计数等功能:
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
print(f"Called {self.count} times")
# 创建一个 Counter 对象
counter = Counter()
# 多次调用
counter() # 输出 "Called 1 times"
counter() # 输出 "Called 2 times"
counter() # 输出 "Called 3 times"
在这个例子中,Counter
对象每次被调用都会增加内部计数,并输出调用次数。通过这种方式,可调用对象既像函数,又具备状态。
总结:
- 定义:在类中实现
__call__
方法可以让对象具备可调用性。 - 调用:直接使用实例调用形式
instance(...)
,就会自动触发__call__
方法。 - 灵活性:可传入任意参数,支持链式调用和状态保存。