在 Python 中,__call__ 是一个特殊方法(Magic Method),用于定义对象被调用时的行为。当我们将一个对象当作函数调用时(如 obj()),Python 会自动调用该对象的 __call__ 方法。
1. 基本用法
通过实现 __call__ 方法,可以让类的实例对象像函数一样被调用。
示例:
class Adder:
def __init__(self, x):
self.x = x
def __call__(self, y):
return self.x + y
# 创建对象
add_5 = Adder(5)
# 调用对象
result = add_5(10) # 相当于调用 add_5.__call__(10)
print(result) # 输出:15
2. 作用场景
__call__ 方法常用于以下场景:
(1) 函数式编程
将对象作为函数使用,便于封装逻辑:
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x):
return x * self.factor
# 创建对象
double = Multiplier(2)
# 调用对象
print(double(5)) # 输出:10
(2) 装饰器
实现装饰器类时,__call__ 用于定义装饰行为:
class Logger:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f"调用函数:{self.func.__name__}")
return self.func(*args, **kwargs)
# 使用装饰器
@Logger
def greet(name):
return f"你好, {name}!"
# 调用函数
print(greet("世界")) # 输出:调用函数:greet \n 你好, 世界!
(3) 状态保持
对象可以保存状态,并在调用时使用:
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
# 创建对象
counter = Counter()
# 调用对象
print(counter()) # 输出:1
print(counter()) # 输出:2
3. 与普通函数的区别
| 特性 | 普通函数 | 实现了 __call__ 的对象 |
|---|---|---|
| 调用方式 | func() | obj() |
| 状态保持 | 无状态(除非使用闭包) | 可保存状态(通过实例属性) |
| 灵活性 | 逻辑固定 | 可动态修改行为(通过方法重写) |
4. 与 __init__ 的区别
| 方法 | 调用时机 | 作用 |
|---|---|---|
__init__ | 对象创建时(构造函数) | 初始化对象属性 |
__call__ | 对象被调用时(如 obj()) | 定义对象被调用时的行为 |
5. 高级用法
(1) 动态修改行为
通过修改 __call__ 方法,可以让对象的行为动态变化:
class DynamicBehavior:
def __init__(self):
self.behavior = "默认行为"
def __call__(self):
return self.behavior
# 创建对象
obj = DynamicBehavior()
# 调用对象
print(obj()) # 输出:默认行为
# 修改行为
obj.behavior = "新行为"
print(obj()) # 输出:新行为
(2) 链式调用
结合其他特殊方法(如 __add__),实现链式调用:
class Chain:
def __init__(self, value):
self.value = value
def __call__(self, func):
self.value = func(self.value)
return self
def __add__(self, other):
return Chain(self.value + other)
# 链式调用
result = Chain(5)(lambda x: x * 2) + 10
print(result.value) # 输出:20
总结
• 核心作用:让对象像函数一样被调用,支持灵活的行为定义。
• 常见场景:函数式编程、装饰器、状态保持。
• 与函数的区别:对象可以保存状态,行为更灵活。
• 与 __init__ 的区别:__init__ 用于初始化,__call__ 用于调用。