为什么调用元类的__new__

时间:2019-05-08 10:32:19

标签: python metaclass

使用Python元类A创建新的类B

C继承自B时,为何调用A的{​​{1}}方法?

__new__
class A(type):
    def __new__(cls, name, bases, attrs):
        print(" call A.__new__  ")
        return type.__new__(cls, name, bases, attrs)


B = A("B", (), {})


class C(B):
    pass                  

1 个答案:

答案 0 :(得分:2)

类是元类的实例,默认元类type是从object派生的。因此,元类遵循创建object实例的常规规则-__new__构造实例,__init__可以对其进行初始化。

>>> class DemoClass(object):
...     def __new__(cls):
...         print('__new__ object of DemoClass')
...         return super().__new__(cls)
...
...     def __init__(self):
...         print('__init__ object of DemoClass')
...         return super().__init__()
...
>>> demo_instance = DemoClass()  # instantiate DemoClass
__new__ object of DemoClass
__init__ object of DemoClass

当我们的类是一个元类时,也会发生同样的事情-它仍然是object并且表现得如此。

>>> class DemoType(type):
...     def __new__(mcs, name, bases, attrs):
...         print('__new__ object %r of DemoType' % name)
...         return super().__new__(mcs, name, bases, attrs)
...
...     def __init__(self, name, bases, attrs):
...         print('__init__ object %r of DemoType' % name)
...         return super().__init__(name, bases, attrs)
...
>>> demo_class = DemoType('demo_class', (), {})  # instantiate DemoType
__new__ object 'demo_class' of DemoType
__init__ object 'demo_class' of DemoType

重申一下,如果aA的实例,则使用A.__new__创建a。类和元类也是如此,因为前者是后者的实例。

一个类不从其元类继承__new__。一个类具有一个元类,并且使用元类的__new__创建该类。


从类(元类的实例)继承时,元类也被继承。这意味着子类也是也是元类的实例。因此,元类的__new____init__都用于构造和初始化此实例。

>>> class DemoClass(metaclass=DemoType):
...     ...
...
>>> class DemoSubClass(DemoClass):
...     ...
...
__new__ object 'DemoClass' of DemoType
__init__ object 'DemoClass' of DemoType
__new__ object 'DemoSubClass' of DemoType
__init__ object 'DemoSubClass' of DemoType
>>> type(DemoClass)  # classes are instances of their metaclass
__main__.DemoType
>>> type(DemoSubClass)  # subclasses inherit metaclasses from base classes
__main__.DemoType

此操作的目的是为define how classes are created存在MetaClass。这包括子类。对每个子类调用__new__可以使元类对新的类主体,其他基础和名称空间以及关键字做出反应。