“元类”,即metaclass,是类的类,类是元类的实例。 python中“一切皆对象“,对象是类的实例化,类本身也是元类的实例。 元类用来控制类的创建,正如类用来控制对象的创建。 type是python中基础的元类,是自定义类默认的元类。

比喻:儿子(子类)继承了父亲(超类),儿子和父亲都属于同一个维度的生物,儿子的行为大多和父亲相似(继承和覆盖),他们都由上帝(元类)创造。

类的创建

class classname:
    pass

class classname 指实例化一个元类的对象,默认的元类是type,相当于调用type(classname, superclass, attributedict),实例化出一个用户自定义的类class。

类的实例化

foo = classname()

类的实例化时,python内部调用了classname的元类(此处为type)的 __call__ 方法,type的默认__call__ 方法会依次调用 __new__ 方法和 __init__ 方法。其中 __new__ 方法分配内存,__init__ 方法初始化对象。 如果 classname 中重写了 __new____init__ 方法,那么type的 __call__ 方法实际调用的是 classname 的方法,否则是type的默认方法。 可以通过重写 classname 的 __new____init__ 方法,控制实例化 classname 时的操作。

自定义元类

class meta(type):
    pass

通过继承基类type,来自定义元类。

class classname(metaclass=meta):
    pass

class classname 指实例化一个元类的对象,此时指定元类是meta,相当于调用meta(classname, superclass, attributedict)进行实例化。和class实例化一个对象类似,底层会调用meta的 __new____init__ 方法,可以重写该方法,控制定义 classname 时的操作。

foo = classname()

已知一个类实现了__call__方法后,它的实例支持以圆括号的形式被调用。

classname() 中,classname是元类type的实例,classname()这个形式是在调用type中定义的__call__ 方法。

所以类的实例化,调用了元类的 __call__ 方法,元类默认的 __call__ 方法又调用了 __new____init__ 方法,可重写该方法,以自定义类的实例化。

例子

In[15]: class Mymeta(type):
   ...:     def __init__(self, name, bases, dic):
   ...:         super().__init__(name, bases, dic)
   ...:         print('===>Mymeta.__init__')
   ...:         print(self.__name__)
   ...:         print(dic)
   ...:         print(self.yaml_tag)
   ...: 
   ...:     def __new__(cls, *args, **kwargs):
   ...:         print('===>Mymeta.__new__')
   ...:         print(cls.__name__)
   ...:         return type.__new__(cls, *args, **kwargs)
   ...: 
   ...:     def __call__(cls, *args, **kwargs):
   ...:         print('===>Mymeta.__call__')
   ...:         obj = cls.__new__(cls)
   ...:         cls.__init__(cls, *args, **kwargs)
   ...:         return obj
   ...: 
In[16]: 
In[16]: class Foo(metaclass=Mymeta):
   ...:     yaml_tag = '!Foo'
   ...: 
   ...:     def __init__(self, name):
   ...:         print('Foo.__init__')
   ...:         self.name = name
   ...: 
   ...:     def __new__(cls, *args, **kwargs):
   ...:         print('Foo.__new__')
   ...:         return object.__new__(cls)
   ...:     
===>Mymeta.__new__
Mymeta
===>Mymeta.__init__
Foo
{'__module__': '__main__', '__qualname__': 'Foo', 'yaml_tag': '!Foo', '__init__': <function Foo.__init__ at 0x0000000007EF3828>, '__new__': <function Foo.__new__ at 0x0000000007EF3558>}
!Foo

In[17]: foo = Foo('foo')
===>Mymeta.__call__
Foo.__new__
Foo.__init__

In[18]:

从上面的运行结果可以发现在定义 class Foo() 定义时,会依次调用 MyMeta 的 __new____init__ 方法构建 Foo 类,然后在调用 foo = Foo() 创建类的实例对象时,才会调用 MyMeta 的 __call__ 方法来调用 Foo 类的 __new____init__ 方法。


<
Previous Post
位操作
>
Next Post
并发执行