引入
# 如果要让一个对象可以加括号调用,需要在该对象的类中添加一个方法__call__
例如:
class People:
def __init__(self, name, age):
self.name = name
self.age = age
obj = People('zs', 18)
obj()
# 报错:TypeError: 'People' object is not callable (People对象不可调用)
此时,people类内部并没有__call__方法,所以无法调用obj。
往People内部加一个__call__方法:
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print("这是call")
return 111
obj = People('zs', 18)
res = obj()
print(res)
# 这是call
# 111
这就实现了开头的需求。
__call__在定制元类中的作用:
# 调用元类产生类会发生的三件事:(与调用类产生对象的步骤一致)
# 1、先生成一个空对象----------调用__new__方法生成的对象
# 2、调用元类下的__init__方法,完成初始化对象的操作
# 3、返回一个初始化好的对象
实际上,调用类产生对象发生的三件事,就是__call__方法在起作用。一个类既然能被调用就说明该类的元类内部实现了__call__方法。
而这三件事(也可以称为三个步骤)就是在__call__方法内依次实现的:
#案例:
调用类产生对象的完整过程 :
对象是People类调用__call__()生成的,__call__是People类的元类控制的
class Mymeta(type):
def __call__(self, *args, **kwargs):
"""
self : 调用者本身(People类)
:param args: 调用对象时传入的参数
:param kwargs: 调用对象时传入的参数
:return: 初始化后的对象
"""
# 先生成一个空对象---- __new__方法(如果调用者本身没有改写new方法,调用的就是默认的new)
people_obj = self.__new__(self)
# 完成对象初始化---- __init__方法
self.__init__(people_obj, *args, **kwargs)
# 返回初始化后的对象----
return people_obj
class People(metaclass=Mymeta):
def __init__(self, name, age):
self.name = name
self.age = age
obj = People('zs', 18)
print(obj.__dict__)
总结:
1、__call__方法控制的是,类产生对象的过程,可以在调用过程中做一些定制化操作;
2、一个对象是否能够调用,取决于它的类或元类是否有__call__方法;
3、类的定制化,需要元类的内部对__new__或__init__方法定制化,最终是通过元类的元类(也就内置元类type)的__call__方法来调用生成类。