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() 检查对象是否可调用。
相关推荐
是Yu欸2 小时前
从Ascend C算子开发视角看CANN的“软硬协同”
c语言·开发语言·云原生·昇腾·ascend·cann·开放社区
黎雁·泠崖2 小时前
C 语言字符串进阶:strcpy/strcat/strcmp 精讲
c语言·开发语言
八月ouc2 小时前
Python实战小游戏(三): 简易文件管理器
python·shutil·文件管理器·os.walk·pathlib
赴前尘2 小时前
golang获取一个系统中没有被占用的端口
开发语言·后端·golang
嘴贱欠吻!2 小时前
JavaSE基础知识
java·开发语言
逝水如流年轻往返染尘3 小时前
Java输入输出
java·开发语言
安冬的码畜日常3 小时前
【玩转 Postman 接口测试与开发2_020】(完结篇)DIY 实战:随书示例 API 项目本地部署保姆级搭建教程(含完整调试过程)
python·测试工具·django·接口测试·postman·fastapi·api项目
hqwest3 小时前
码上通QT实战03--登录逻辑
开发语言·qt·登录·嵌入式实时数据库·界面设计