__call__ 是一个很神奇的特性,只要某个类型中有 __call__ 方法,就可以把这个类型的对象当作函数来使用。
f = abs
'__call__' in dir(f)
True
上例中的 f 对象指向了 abs 类型,由于 f 对象中有__call__方法,
因此 f(-10) 实现了对 abs(-10) 的重载。
f(-10)
10
由于变量/对象/实例可以指向函数,而函数能够接受变量,
因此可以看出函数可以接受另一个函数作为参数,所以__call__就实现装饰器的基础。
函数或类一般有返回值,而python中有一个神奇的特性就是返回函数。
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f = lazy_sum(1,3,5,7,9)
f
<function __main__.lazy_sum.<locals>.sum()>
'__call__' in dir(f)
True
f()
25
为什么返回函数能够这么神奇,咱们一探究竟。
dir(f)
['__annotations__',
'__call__',
'__class__',
...
'__getattribute__',
...
'__setattr__',
]
查看一下 type ,真相打败,原来是因为f里有__call__的内建方法。