Python __call__() 方法

Python __call__() 语法

__call__() 是 Python 的一个特殊方法(又称 “魔法方法” 或 “双下划线方法”),它允许一个类的实例像函数一样被调用。

也就是说,如果一个类实现了 __call__() 方法,那么它的实例就成为了可调用对象。

语法:

class MyObject:
    def __call__(self, *args, **kwargs):
        # 实例被调用时的实现
        return value

说明:

__call__() 方法除了 self(实例本身)之外,可以接收任意数量的位置参数 (*args) 和关键字参数 (**kwargs),就像普通函数一样。

  • self(必选) :约定俗成的名称,表示实例对象。
  • *args(可选) :一个元组,包含所有传递给实例的位置参数。
  • **kwargs(可选) :一个字典,包含所有传递给实例的关键字参数。

__call__() 方法的返回值可以是任何类型,取决于其实现的逻辑。

对于 __call__() 方法来说,它常用于实现:

  • 函数对象(Function Objects)或函子(Functors):封装状态的函数,每次调用都能利用这些状态。
  • 装饰器(Decorators):当装饰器类被实例化并用于修饰函数时。
  • 类工厂(Class Factories):根据不同参数创建或返回不同类型的实例。
  • 具有定制行为的对象:例如,一个配置对象,可以通过调用来触发更新或返回特定配置。

Python __call__() 摘要

属于 Python 魔法方法
使用频率
官方文档 查看
相关函数 callable()

Python __call__() 示例

接下来,我们通过几个简单的例子来讲解一下 Python __call__() 方法是如何使用的。

示例 1:__call__() 使对象变得可调用

class Greeter:
    def __init__(self, greeting):
        self.greeting = greeting

    def __call__(self, name):
        return f'{self.greeting}, {name}!'

# 创建 Greeter 实例
greeter = Greeter('Hello')

# 像函数一样调用实例
print(greeter('Jack'))

# 检查对象是否可调用
print(callable(greeter))

运行结果如下。

Hello, Jack!
True

分析:

在这个例子中,我们定义了一个名为 “Greeter” 的类,并在其内部实现了 __call__() 方法。因此 Greeter 类的实例 greeter 会变得可调用。

也就是说,我们可以像调用函数一样来调用 greeter()。当 Greeter('Hello') 被调用时,实际上就触发了 greeter 实例的 __call__() 方法。

此外,我们还可以使用 callable() 函数来判断一个对象是否实现了 __call__() 方法。

示例 2:__call__() 作为状态机或计数器

class Counter:
    def __init__(self, initial_value=0):
        self.count = initial_value

    def __call__(self):
        self.count += 1
        return self.count

# 创建计数器实例
first_counter = Counter()

# 每次调用实例,计数器值增加
print(first_counter())     # 1
print(first_counter())     # 2
print(first_counter())     # 3

another_counter = Counter(10)
print(another_counter())      # 11
print(another_counter())      # 12

运行结果如下。

1
2
3
11
12

分析:

在这个例子中,Counter 类的实例充当了一个简单的计数器。每次调用 my_counter(),它内部的 count 属性就会递增,并返回当前值。

示例 3:__call__() 用于实现装饰器

class MyDecorator:
    def __init__(self, fn):
        self.fn = fn

    def __call__(self, *args, **kwargs):
        print('在函数调用之前执行一些操作...')
        result = self.fn(*args, **kwargs)
        print('在函数调用之后执行一些操作...')
        return result

@MyDecorator
def hello(name):
    print(f'Hello, {name}!')
    return f'Result for {name}'

@MyDecorator
def add(a, b):
    print(f'Calculating {a} + {b}...')
    return a + b

hello('Jack')
result = add(10, 20)
print(result)

运行结果如下。

在函数调用之前执行一些操作...
Hello, Jack!
在函数调用之后执行一些操作...

在函数调用之前执行一些操作...
Calculating 10 + 20...
在函数调用之后执行一些操作...

30

分析:

MyDecorator 是一个 装饰器。当 hello() 函数被 @MyDecorator 装饰时,hello() 函数本身会被作为参数传递给 MyDecorator 的 __init__() 方法,并创建一个 MyDecorator 的实例。

然后,每当调用 hello 时,实际上就是调用了 MyDecorator 实例的 __call__() 方法,该方法在执行原始函数前后添加了额外的逻辑。

示例 4:带有参数的 __call__()

class Calculator:
    def __call__(self, operation, a, b):
        if operation == 'add':
            return a + b
        elif operation == 'subtract':
            return a - b
        else:
            raise ValueError('不支持的操作')

# 创建计算器实例
calc = Calculator()

# 像函数一样调用实例,并传递参数
print(calc("add", 20, 10))
print(calc("subtract", 20, 10))

try:
    print(calc('multiply', 4, 8))
except ValueError as e:
    print(e)

运行结果如下。

30
10
不支持的操作

分析:

__call__() 方法可以像一个普通函数一样接收不同的参数。Calculator 实例被调用时,根据传入的 operation 参数执行不同的计算。这样可以使得一个对象能够封装多种不同行为,并以统一的函数调用方式来对外暴露。

上一篇: __bool__()

下一篇: __getattr__()

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号