在 Python 中,__call__ 是一个特殊的魔术方法,用于让实例对象可以像函数一样被调用 。当实例被当作函数调用时,Python 解释器会自动调用该实例的 __call__ 方法。通过实现 __call__,可以让对象具备 "可调用" 的特性,模糊了函数和对象之间的边界,常用于实现装饰器 、工厂模式 、状态保持等场景。
基本语法
在类中定义 __call__ 方法的语法如下:
python
运行
class MyClass:
def __call__(self, *args, **kwargs):
# 实现调用逻辑
pass
self:表示实例本身。*args和**kwargs:接收调用实例时传入的参数,与普通函数的参数规则一致。
基础示例
当实例被调用时,__call__ 方法会被执行:
python
运行
class Counter:
def __init__(self):
# 初始化计数器
self.count = 0
def __call__(self):
# 每次调用实例,计数器加1
self.count += 1
print(f"调用次数: {self.count}")
# 创建实例
counter = Counter()
# 像调用函数一样调用实例
counter() # 输出:调用次数: 1
counter() # 输出:调用次数: 2
counter() # 输出:调用次数: 3
在这个例子中,counter 是 Counter 类的实例,但通过 counter() 调用时,会自动执行 __call__ 方法,实现了计数器的累加。
带参数的 call 方法
__call__ 可以接收参数,用法与普通函数一致:
python
运行
class Calculator:
def __call__(self, a, b, op="+"):
if op == "+":
return a + b
elif op == "-":
return a - b
elif op == "*":
return a * b
elif op == "/":
return a / b if b != 0 else "除数不能为0"
# 创建实例
calc = Calculator()
# 调用实例并传入参数
print(calc(10, 5)) # 输出:15(默认加法)
print(calc(10, 5, "-")) # 输出:5
print(calc(10, 5, "*")) # 输出:50
print(calc(10, 0, "/")) # 输出:除数不能为0
检查对象是否可调用
可以使用内置函数 callable() 判断一个对象是否为 "可调用对象"(实现了 __call__ 方法的实例、函数、类等都属于可调用对象):
python
运行
class MyClass:
def __call__(self):
pass
obj = MyClass()
print(callable(obj)) # 输出:True(实现了__call__)
print(callable(MyClass))# 输出:True(类本身是可调用的,调用后创建实例)
print(callable(123)) # 输出:False(整数不可调用)
print(callable(lambda x: x+1)) # 输出:True(lambda是函数)
典型应用场景
1. 实现装饰器
利用 __call__ 可以实现带状态的装饰器(相比普通函数装饰器,类装饰器更易维护状态):
python
运行
class TimerDecorator:
def __init__(self, func):
self.func = func
self.call_count = 0 # 记录函数被调用的次数
def __call__(self, *args, **kwargs):
self.call_count += 1
import time
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print(f"函数 {self.func.__name__} 第 {self.call_count} 次调用,耗时: {end - start:.6f} 秒")
return result
# 使用装饰器
@TimerDecorator
def add(a, b):
return a + b
add(1, 2)
add(3, 4)
2. 实现工厂模式
通过 __call__ 封装对象的创建逻辑,实现动态生成实例:
python
运行
class AnimalFactory:
def __init__(self):
self.animals = {}
def register(self, animal_type, animal_class):
# 注册动物类
self.animals[animal_type] = animal_class
def __call__(self, animal_type, *args, **kwargs):
# 创建动物实例
if animal_type not in self.animals:
raise ValueError(f"未知的动物类型: {animal_type}")
return self.animals[animal_type](*args, **kwargs)
# 定义动物类
class Dog:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name}: 汪汪汪"
class Cat:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name}: 喵喵喵"
# 创建工厂并注册动物
factory = AnimalFactory()
factory.register("dog", Dog)
factory.register("cat", Cat)
# 通过工厂创建实例(调用factory实例)
dog = factory("dog", "旺财")
cat = factory("cat", "咪宝")
print(dog.speak()) # 输出:旺财: 汪汪汪
print(cat.speak()) # 输出:咪宝: 喵喵喵
总结
__call__让类的实例可以像函数一样被调用,执行__call__中的逻辑。- 支持传入参数,参数规则与普通函数一致。
- 常用于实现带状态的装饰器 、工厂模式 、函数式对象等场景。
- 可通过
callable()检查对象是否可调用。