除了用户定义的函数,调用运算符(即 ())还可以应用到其他对象上。如果想判断对象能否调用,可以使用内置的 callable() 函数。Python 数据模型文档列出了 7 种可调用对象。
- 使用 def 语句或 lambda 表达式创建
- 内置函数:使用 C 语言(CPython)实现的函数,如 len 或 time.strftime。
- 内置方法:使用 C 语言实现的方法,如 dict.get。
- 方法:在类的定义体中定义的函数。
- 类:调用
类时会运行类的__new__方法创建一个实例,然后运行__init__方法,初始化实例,最后把实例返回给调用方。因为Python没有new运算符,所以调用类相当于调用函数。 - 类的实例: 如果类定义了
__call__方法,那么它的实例可以作为函数调用。 - 生成器函数: 使用
yield关键字的函数或方法。调用生成器函数返回的是生成器对象。
用户定义的可调用类型
不仅 Python 函数是真正的对象,任何 Python 对象都可以表现得像函数。为此,只需实现实例方法 __call__。
import random
class 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())
# 0
print(bingo())
# 2
print(callable(bingo))
# True
实现 __call__ 方法的类是创建函数类对象的简便方式,此时必须在内部维护一个状态,让它在调用之间可用,例如 BingoCage 中的剩余元素。装饰器就是这样。装饰器必须是函数,而且有时要在多次调用之间“记住”某些事 [ 例如备忘(memoization),即缓存消耗大的计算结果,供后面使用。
创建保有内部状态的函数,还有一种截然不同的方式——使用闭包
本文介绍了Python中各种可调用对象,包括函数、内置函数、内置方法、类的__call__方法、生成器函数以及如何通过BingoCage类和装饰器实现自定义可调用行为。还提到了闭包作为一种创建保持内部状态函数的方式。
195

被折叠的 条评论
为什么被折叠?



