1 什么是 可调用的,什么是不可调用的?

概念介绍

什么叫可调用,这个对象,可以 通过某种方法 执行,或者说 对象.(args,kw) 如果这个方法 可以执行 那么我们就说 这个对象是可调用的。
在python中最常见的 比如函数 ,方法 ,这些都是可以调用的 因为这些都可以通过上述方法执行 。
函数是可调用的吗? 比如我定义一个函数,他可以通过 函数名() 这种方式 执行 函数里面的代码段,这个函数我们就说 是可以调用的。
还有一个更加直观的方法 就是 直接 使用
系统内置函数callable*
来判断是不是可调用的。这个函数返回 True 就表明这个 函数是可调用的。

  1. >>> def pickup():
  2. ... pass
  3. ...
  4. >>> pickup()
  5. >>> callable(pickup)
  6. True

类是可调用的吗

咱们来说一下类 , 你觉得类 是可调用的吗? 由类生成的对象 是可调用的吗?
—首先说一下 结论 ,对于这个类而言 , Person 类 是可调用的。而由Person 生成的对象 是不可调用的。

  1. >>> class Person:
  2. ... def __init__(self, name='frank'):
  3. ... self.name = name
  4. ... def sing(self):
  5. ... print(f"{self.name} is singing")
  6. ...
  7. >>> callable(Person)
  8. True
  9. >>> p = Person()
  10. >>> callable(p)
  11. False
  12. >>> p()
  13. Traceback (most recent call last):
  14. File "<input>", line 1, in <module>
  15. TypeError: 'Person' object is not callable
  16. >>> callable(p.sing)
  17. True
  18. >>> p.sing()
  19. frank is singing

首先还是用刚刚我说的方法 判断 , Person 是不是可调用的, 只要看看 Person(args,**kw) 这个能不能正常执行, 很明显 是可以执行, 用它来构造一个Person 的对象 p , 所以 我们 说 Person 是可以执行的 。
对于对象p 而言 ,只要看p(
arg,kw) 能不能执行, 显然 这个例子 不能执行 。 所以我们说 对象 p 不能调用。而对于对象p的 成员方法 sing而言 , p.sing() 这个显然 是可以执行的, 所以 对象p的成员方法 sing 是可以调用的。
那么问题来了, 对于一个对象 如何 从一个 不可调用 转换成 可调用的呢? 就是 实现
魔术方法 call**稍微改造一下这个类,让 p 变成一个 可调用的对象

  1. class Person:
  2. def __init__(self, name='frank'):
  3. self.name = name
  4. def sing(self):
  5. print(f"{self.name} is singing")
  6. # 添加这个魔术方法
  7. def __call__(self, *args, **kwargs):
  8. self.sing()
  9. >>> p = Person()
  10. >>> p
  11. <__main__.Person object at 0x000001786F29BBC8>
  12. >>> callable(p)
  13. True
  14. >>> p()
  15. 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函数,这个类型就成为可调用的。 换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。我们可以 实例对象()

  1. class TestCall(object):
  2. def __init__(self, name):
  3. self.name = name
  4. def __call__(self, *args, **kwargs):
  5. print("self.name: %s. " % self.name, end=' ')
  6. print('__call__() is running ')
  7. if __name__ == '__main__':
  8. call = TestCall(name='xiaoming')
  9. call() # call.__call__()
  10. call.__call__()

结果:

  1. self.name: xiaoming. __call__() is running
  2. self.name: xiaoming. __call__() is running
  3. # call() 就等价于 call.__call()__ 这样的调用

4 总结