除了
用户定义的函数
,调用运算符
(即 ()
)还可以应用
到其他对象
上。如果想判断
对象能否调用,可以使用内置的 callable()
函数。Python
数据模型文档列出了 7 种可调用对象。
- 使用 def 语句或 lambda 表达式创建
- 内置函数:使用 C 语言(CPython)实现的函数,如 len 或 time.strftime。
- 内置方法:使用 C 语言实现的方法,如 dict.get。
- 方法:在类的定义体中定义的函数。
- 类:调用
类
时会运行类的__new__
方法创建一个实例
,然后运行__init__
方法,初始化
实例,最后把实例返回给调用方
。因为Python
没有new
运算符,所以调用类相当于
调用函数。 - 类的实例: 如果类定义了
__call__
方法,那么它的实例可以作为函数调用。 - 生成器函数: 使用
yield
关键字的函数
或方法
。调用生成器
函数返回的是生成器对象
。
用户定义的可调用类型
不仅 Python
函数是真正的对象
,任何 Python
对象都可以
表现得像函数
。为此,只需
实现实例方法 __call__
。
import randomclass BingoCage:def __init__(self, items):# __init__ 接受任何可迭代对象;在本地构建一个副本,防止列表参数的意外副作用。self._items = list(items)# shuffle 定能完成工作,因为 self._items 是列表。random.shuffle(self._items)def pick(self): # 起主要作用的方法。try:return self._items.pop()except IndexError: # 如果 self._items 为空,抛出异常,并设定错误消息。raise LookupError('pick from empty BingoCage')def __call__(self): # bingo.pick() 的快捷方式是 bingo()return self.pick()if __name__ == '__main__':bingo = BingoCage(range(3))print(bingo.pick())# 0print(bingo())# 2print(callable(bingo))# True
实现 __call__
方法的类
是创建函数类对象
的简便方式
,此时必须
在内部维护一个状态,让它在调用之间可用,例如 BingoCage
中的剩余元素。装饰器
就是这样。装饰器
必须是函数,而且有时要在多次调用之间“记住
”某些事 [ 例如备忘(memoization
),即缓存
消耗大的计算结果,供后面使用。
创建保有内部状态的函数
,还有一种截然不同的方式——使用闭包