导语
大家都知道类经过实例化,可以生成类的实例但是他究竟是一个什么过程呢?既然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类的创建过程,实例化过程,以及元类的相关知识,利用这三个方法和元类我们可以更好的控制类的创建和实例化过程。
这篇文章就先写到这里,后边有机会,我们可以再谈一谈,我们究竟可以利用这些过程,和元类达到什么目的。