一文搞懂python元类、类、实例、__new__、__init__、__call__之间的联系

导语

大家都知道类经过实例化,可以生成类的实例但是他究竟是一个什么过程呢?既然python是面向对象的一种解释型语言,那么python类本身是否也是一个对象呢?那么这个对象是由什么创建的呢?又经过什么过程创建的呢?下面一一进行解答。

1.类

我们都知道类是面向对象语言的最基本概念,对于python来讲也是如此。下面定义一个最简单的类:

class MyClass:
    def __init__(self,*args):
        print('调用了__init__方法','参数是',*args)


if __name__ == '__main__':
    MyClass(123,'abcd')

运行代码我们可以发现终端打印出了“调用了__init__方法 参数是 123 abcd”,也就是说在实例化类的时候,程序调用了init方法,下面我们重写new方法

class MyClass:
    def __init__(self,*args):
        print('调用了__init__方法','参数是',*args)

    def __new__(cls, *args):
        print('调用了__new__方法','参数是',*args)
        obj = super().__new__(cls)
        print(obj)
        print(type(obj))
        return obj


if __name__ == '__main__':
    MyClass(123,'abcd')

下面观察打印结果,我们可以看到new方法的调用在init方法之前,且此时实例对象此时还没有被创建,当调用了父类的new方法之后,这个时候实例对象才被创建,且此时实例还没有初始化。那么创建一个实例对象为什么会是先调用new方法再调用init方法呢?这个我们后边谈元类的时候会提及。

下面我们再定义__call__方法,并执行代码

class MyClass:
    def __init__(self,*args):
        print('调用了__init__方法','参数是',*args)

    def __new__(cls, *args):
        print('调用了__new__方法','参数是',*args)
        obj = super().__new__(cls)
        print(obj)
        print(type(obj))
        return obj

    def __call__(self, *args):
        print('调用了__call__方法','参数是',*args)


if __name__ == '__main__':
    my_class = MyClass(123,'abcd')
    print('--------------------')
    my_class('qwer')

我们可以发现,当执行到my_class('qwer')时,调用了我们定义的call方法。所以当我们在类中定义了call方法时,我们称这个类的实例都是可callable的对象。这里我们发现了一个有趣的现象MyClass(123,'abcd')和my_class('qwer')这两段代码如此相像,那么是不是MyClass这个类也可以称为可callable的呢?他是不是也调用了创建他的那个“东西”的call方法呢?答案是对的,这个东西就叫元类,即创建类的类,下面我们简单讲一下元类。

2.元类

首先简单来了解下元类,通俗的将元类的使命就是创建类,类似于“类加载器”一类的东西,我们自定义的元类需要继承type类。即我们平时经常使用的type就是元类。下面我们继承type来写一个我们自己的元类,并且将我们的MyClass的元类指定为我们自己定义的这个元类。

class MyMetaClass(type):
    def __init__(cls,*args,**kwargs):
        print('执行了元类的init方法','参数是',args,kwargs)
        super().__init__(*args,**kwargs)

    def __new__(mcs,*args,**kwargs):
        print('执行了元类的new方法','参数是',args,kwargs)
        cls = super().__new__(mcs,*args,**kwargs)
        print(cls)
        return cls

    def __call__(cls, *args):
        print('执行了元类的call方法','参数是',args)
        return super().__call__(*args)


class MyClass(metaclass=MyMetaClass):
    def __init__(self,*args):
        pass
        # print('调用了__init__方法','参数是',*args)

    def __new__(cls, *args):
        # print('调用了__new__方法','参数是',*args)
        obj = super().__new__(cls)
        # print(obj)
        # print(type(obj))
        return obj

    def __call__(self, *args):
        pass
        # print('调用了__call__方法','参数是',*args)


if __name__ == '__main__':
    print("实例化MyClass")
    my_class = MyClass(123,'abcd')

我们可以看到MyClass这个类一旦创建,先执行创建这个类的元类的new方法,然后执行元类的init方法,当类进行实例化时,调用元类的call方法。这里我们就可以进行填坑了,前边类实例化的时候为什么先执行new方法然后执行init方法,因为创建这个类的元类里边的call方法就是这么定义的。下面我们可以将类创建、类调用(本质上就是类实例化)和类实例化、实例调用的过程进行对比。

总结

__new__、__init__、__call__三个特殊方法是我们日常经常会用到的,这里我们从这三个方法开始谈到了python类的创建过程,实例化过程,以及元类的相关知识,利用这三个方法和元类我们可以更好的控制类的创建和实例化过程。

这篇文章就先写到这里,后边有机会,我们可以再谈一谈,我们究竟可以利用这些过程,和元类达到什么目的。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值