python中元类在创建类和实例的作用
最近在研究backtrader的底层源代码,作者用类若干的类和元类,以前没有接触过元类,现在经过查了一些资料,知道了元类是创建类的类,可以用来控制类的创建和实例的创建过程,也可以隐性地继承属性和方法,元类的常见的应用有创建单类模式、ORM。 由于元类的理解比较抽象,可以用下面的代码理解元类在创建类和实例时的作用,
- metaClass1: 继承自type类的元类
- metaClass2: 继承自metaClass1的元类
- A: 由metaClass1创建的类
- M:继承自A的子类
- a: 类A的实例化对象
- m: 类M的实例化对象
class metaClass1(type):
def __new__(cls, clsname, bases, dct):
print("基于type的类metaClass1,....__new__")
return type.__new__(cls, clsname, bases, dct)
def __call__(self, *args, **kwargs):
print("基于type的类metaClass1,....__call__")
return super().__call__(*args, **kwargs)
class metaClass2(metaClass1):
def __new__(cls, clsname, bases, dct):
print("基于metaClass1的类metaClass2,....__new__")
return super().__new__(cls, clsname, bases, dct)
def __call__(self, *args, **kwargs):
print("基于metaClass1的类metaClass2,....__call__")
return super().__call__(*args, **kwargs)
print("创建类A-------")
class A(metaclass=metaClass2):
def __new__(cls, *agrs, **kwds):
inst = super().__new__(cls, *agrs, **kwds)
print("由metaClass2创建的类A,....__new__...正在创建类的实例")
return inst
def __init__(self):
print("由metaClass2创建的类A,....__init__...正在创建类的实例")
super().__init__()
class metaClass3(type):
def __new__(cls, clsname, bases, dct):
print("基于metaClass1的类metaClass2,....__call__")
return super().__new__(cls, clsname, bases, dct)
print('创建A的子类M-------')
class M(A, metaclass=type):
def __new__(cls, *agrs, **kwds):
print("类A的子类M,...__new__...正在创建类的实例")
return super().__new__(cls, *agrs, **kwds)
def __init__(self):
print("类A的子类M,...__init__...正在创建类的实例")
super().__init__()
print("创建A的实例--------")
a = A()
print("创建M的实例--------")
m = M()
输出
创建类A-------
基于metaClass1的类metaClass2,....__new__
基于type的类metaClass1,....__new__
创建A的子类M-------
基于metaClass1的类metaClass2,....__new__
基于type的类metaClass1,....__new__
创建A的实例--------
基于metaClass1的类metaClass2,....__call__
基于type的类metaClass1,....__call__
由metaClass2创建的类A,....__new__...正在创建类的实例
由metaClass2创建的类A,....__init__...正在创建类的实例
创建M的实例--------
基于metaClass1的类metaClass2,....__call__
基于type的类metaClass1,....__call__
类A的子类M,...__new__...正在创建类的实例
由metaClass2创建的类A,....__new__...正在创建类的实例
类A的子类M,...__init__...正在创建类的实例
由metaClass2创建的类A,....__init__...正在创建类的实例
分析
这里由两条关系:父类-子类继承关系、元类-类创建关系。
创建类
通过元类创建类时,子类M不必另外声明元类,因为创建M时,会默认调用父类A的元类,如果设置metaclass为父类的元类外的别的元类,程序会出错。用元类创建类时,依次调用元类的__new__方法,该方法的参数分别为:
- cls:类对象,类似class中的self
- clsname: 类名,就像例子中的“A”、“M”
- bases:类的父类
- dct:类的属性,是一个字典
通过这些参数可以看出,这是在得到类的属性后才会进入到元类中。
创建实例
创建实例涉及到类的__init__、__new__和元类的__call__。
- __call__:首先调用父类的该方法,如果元类有继承关系,先依次(子元类->父元类)调用完所有元类的__call__方法,接着调用类的__new__方法
- __new__:调用完元类的__new__方法后,接着调用类的__new__,如果类有继承关系,则依次(子类->父类)调用完所有类的__new__方法
- __init__:调用完所有类的__new__方法后,接着调用类的__init__,如果有类的继承关系,则依次(子类->父类)调用所有类的__init__方法