可调用对象
我们知道在Python中,函数是一个对象。由于函数可以被调用,所以函数被称为可调用对象。所有的函数都是可调用对象。可调用对象的一个特点是直接可以使用“对象名(参数列表)”这样的形式运行,即把一对括号()应用到某个对象身上。
>>> def fun():
... pass
...
>>> dir(fun)
['__annotations__', '__call__', '__class__','__closure__', '__code__', '__defaults__', '__delattr__', '__dict__','__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__','__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__','__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__','__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__','__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>>
函数之所以可以被调用,是因为其有一个特殊的属性__call__。
>>> hasattr(fun,"__call__")
True
>>>
还可以使用callable函数进行验证,如
>>> callable(fun)
True
>>>
实际上python中存在以下几种可调用对象
用户定义的函数,如使用 def 语句或 lambda 表达式创建
内置函数,使用 C 语言(CPython)实现的函数,如 len、sorted
方法,类中定义的函数
类,调用类时会运行类的 __new__方法创建一个实例,然后运行 __init__方法,初始化实例,最后把实例返回给调用方。
生成器,使用 yield 关键字的函数或方法。
而类实例对象是不可调用,无法直接使用class_instance(args_list)。但可以在类中实现一个__call__方法,使它的类实例变成可调用对象。
它的作用是让类对象生成的实例对象可以函数一样调用。它重载了()功能,当实例对象带括号()调用时,被 __call__ 这个方法钩住(所谓的钩子),也就是说实例对象带括号()调用的是__call__这个方法。如果__call__()带参数,实例对象括号内必须也要带参数。
#Person类实例变成一个可调用对象
>>> class Person(object):
... def __init__(self, name, gender):
... self.name = name
... self.gender = gender
...
... def __call__(self, friend):
... print 'My name is %s...' % self.name
... print 'My friend is %s...' % friend
>>> p = Person('Bob','male')
>>> p()
Traceback (most recent call last):
File "", line 1, in ?
TypeError: __call__() takesexactly 2 arguments (1 given)
>>>
>>> p('Tim')
My name is Bob...
My friend is Tim...
>>> callable(p)
True
单看 p('Tim') 无法确定 p 是一个函数还是一个类实例。
python中的__call__允许程序员创建可调用的对象(实例),默认情况下__call__()方法是没有实现的,这意味着大多数实例是不可调用的。然而,如果在类定义中覆盖了这个方法,那么这实际上一个类实例就可以变成一个可调用对象。