Почему метакласс __new__ называется - PullRequest
1 голос
/ 08 мая 2019

Используйте метакласс Python A для создания нового класса B.

Когда C наследуется от B, почему вызывается метод A __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                  
python test.py 
call A.__new__  
call A.__new__  

1 Ответ

2 голосов
/ 08 мая 2019

Классы являются экземплярами метаклассов, а метакласс по умолчанию 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

Повторюсь, если a является экземпляром A, то 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

Цель этого состоит в том, что существуют метаклассы, которые определяют, как создаются классы . Это включает в себя подклассы. Вызов __new__ для каждого подкласса позволяет метаклассу реагировать на тело нового класса, дополнительные базы, пространство имен и ключевые слова.

...