1 什么是 可调用的,什么是不可调用的?
概念介绍
什么叫可调用,这个对象,可以 通过某种方法 执行,或者说 对象.(args,kw) 如果这个方法 可以执行 那么我们就说 这个对象是可调用的。
在python中最常见的 比如函数 ,方法 ,这些都是可以调用的 因为这些都可以通过上述方法执行 。
函数是可调用的吗? 比如我定义一个函数,他可以通过 函数名() 这种方式 执行 函数里面的代码段,这个函数我们就说 是可以调用的。
还有一个更加直观的方法 就是 直接 使用系统内置函数callable* 来判断是不是可调用的。这个函数返回 True 就表明这个 函数是可调用的。
>>> def pickup():
... pass
...
>>> pickup()
>>> callable(pickup)
True
类是可调用的吗
咱们来说一下类 , 你觉得类 是可调用的吗? 由类生成的对象 是可调用的吗?
—首先说一下 结论 ,对于这个类而言 , Person 类 是可调用的。而由Person 生成的对象 是不可调用的。
>>> class Person:
... def __init__(self, name='frank'):
... self.name = name
... def sing(self):
... print(f"{self.name} is singing")
...
>>> callable(Person)
True
>>> p = Person()
>>> callable(p)
False
>>> p()
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'Person' object is not callable
>>> callable(p.sing)
True
>>> p.sing()
frank is singing
首先还是用刚刚我说的方法 判断 , Person 是不是可调用的, 只要看看 Person(args,**kw) 这个能不能正常执行, 很明显 是可以执行, 用它来构造一个Person 的对象 p , 所以 我们 说 Person 是可以执行的 。
对于对象p 而言 ,只要看p(arg,kw) 能不能执行, 显然 这个例子 不能执行 。 所以我们说 对象 p 不能调用。而对于对象p的 成员方法 sing而言 , p.sing() 这个显然 是可以执行的, 所以 对象p的成员方法 sing 是可以调用的。
那么问题来了, 对于一个对象 如何 从一个 不可调用 转换成 可调用的呢? 就是 实现魔术方法 call**稍微改造一下这个类,让 p 变成一个 可调用的对象
class Person:
def __init__(self, name='frank'):
self.name = name
def sing(self):
print(f"{self.name} is singing")
# 添加这个魔术方法
def __call__(self, *args, **kwargs):
self.sing()
>>> p = Person()
>>> p
<__main__.Person object at 0x000001786F29BBC8>
>>> callable(p)
True
>>> p()
frank is singing
这个时候 可以通过 p() 这种方式 执行代码,我们就认为 对象 p 是可调用的。 当我们 执行 p() 实际上 执行就是魔术方法 call 里面 的代码 ,这里等同于 是这样的调用关系 p() == p._call()
2 python中可被调用的对象
1 用户自定义的函数:使用def语句或者lambda表达式创建的函数。
2 内置函数:使用C语言实现的函数,如len、sum或者time.strftime
3 内置方法:使用C语言实现的方法,如dict.get()
4 类方法:在类的定义体中定义的函数
5 类:在调用类时会运行类的new方法创建一个实例,然后运行init方法,初始化实例,最后把实例返回给调用方。Python中没有new运算符,所以调用类相当于调用函数。
6 生成器函数:使用yield关键字的函数或方法。调用生成器函数返回的是生成器对象。
7 类的实例:如果类定义了call方法,那么它的实例可以作为函数进行调用。并且call方法可以进行自定义重写。
3 call简单介绍
只要定义类型的时候,实现call函数,这个类型就成为可调用的。 换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。我们可以 实例对象()
class TestCall(object):
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print("self.name: %s. " % self.name, end=' ')
print('__call__() is running ')
if __name__ == '__main__':
call = TestCall(name='xiaoming')
call() # call.__call__()
call.__call__()
结果:
self.name: xiaoming. __call__() is running
self.name: xiaoming. __call__() is running
# call() 就等价于 call.__call()__ 这样的调用
4 总结
- 一般情况 在python 中 函数,方法 类 都是可调用的 。至于 由类生成的对象,是否 是可调用的,主要是看 类中是否实现 魔术方法 call 。
- 当一个类型实现了特殊方法call,该类的实例就变成了可调用的类型, 对象名() 等价于 对象名.call() ,有时候可以简化对象的调用,让对象变成可调用的对象, 实现call即可.
主要来自
https://blog.csdn.net/u010339879/article/details/80588403
https://blog.csdn.net/u010339879/article/details/105065270