yamx

定制元类来控制类的产生之__call__

引入

# 如果要让一个对象可以加括号调用,需要在该对象的类中添加一个方法__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__方法来调用生成类。


评论

© yamx | Powered by LOFTER