python :__call__方法

在 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

在这个例子中,counterCounter 类的实例,但通过 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() 检查对象是否可调用。
相关推荐
tjjucheng17 小时前
靠谱的小程序定制开发哪个好
python
num_killer17 小时前
小白的Langchain学习
java·python·学习·langchain
WangYaolove131417 小时前
基于深度学习的中文情感分析系统(源码+文档)
python·深度学习·django·毕业设计·源码
你怎么知道我是队长18 小时前
C语言---头文件
c语言·开发语言
期待のcode18 小时前
Java虚拟机的运行模式
java·开发语言·jvm
hqwest18 小时前
码上通QT实战25--报警页面01-报警布局设计
开发语言·qt·qwidget·ui设计·qt布局控件
a程序小傲18 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
HellowAmy18 小时前
我的C++规范 - 玩一个小游戏
开发语言·c++·代码规范
自学不成才18 小时前
深度复盘:一次flutter应用基于内存取证的黑盒加密破解实录并完善算法推理助手
c++·python·算法·数据挖掘
徐先生 @_@|||19 小时前
Palantir Foundry 五层架构模型详解
开发语言·python·深度学习·算法·机器学习·架构