__call__ 函数

186 阅读2分钟

在 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__ 用于调用。