В чем разница между типом и типом .__ new__ в python?

Я писал метакласс и случайно сделал это так:

class MetaCls(type): def __new__(cls, name, bases, dict): return type(name, bases, dict) 

… вместо этого:

 class MetaCls(type): def __new__(cls, name, bases, dict): return type.__new__(cls, name, bases, dict) 

В чем же разница между этими двумя метаклассами? И более конкретно, что заставило первый работать некорректно (некоторые классы не были вызваны метаклассом)?

    6 Solutions collect form web for “В чем разница между типом и типом .__ new__ в python?”

    В первом примере вы создаете совершенно новый класс:

     >>> class MetaA(type): ... def __new__(cls, name, bases, dct): ... print 'MetaA.__new__' ... return type(name, bases, dct) ... def __init__(cls, name, bases, dct): ... print 'MetaA.__init__' ... >>> class A(object): ... __metaclass__ = MetaA ... MetaA.__new__ >>> 

    в то время как во втором случае вы вызываете родительский __new__ :

     >>> class MetaA(type): ... def __new__(cls, name, bases, dct): ... print 'MetaA.__new__' ... return type.__new__(cls, name, bases, dct) ... def __init__(cls, name, bases, dct): ... print 'MetaA.__init__' ... >>> class A(object): ... __metaclass__ = MetaA ... MetaA.__new__ MetaA.__init__ >>> 

    Первое, что вам нужно выяснить, – это то, как работает объект .__ new __ ().

    вот :

    https://docs.python.org/3/reference/datamodel.html?highlight=__new__#object.__new__

    объект .__ новый __ (cls [, …])

    Вызывается для создания нового экземпляра класса cls. __new __ () – статический метод (специально обжатый, поэтому вам не нужно объявлять его как таковой), который принимает класс, для которого экземпляр был запрошен как его первый аргумент. Остальные аргументы – это те, которые передаются выражению конструктора объекта (вызов класса). Возвращаемое значение __new __ () должно быть экземпляром нового объекта (обычно это экземпляр cls).

    Типичные реализации создают новый экземпляр класса, вызывая метод __new __ () суперкласса, используя super (currentclass, cls) .__ new __ (cls [, …]) с соответствующими аргументами, а затем, при необходимости, модифицируя вновь созданный экземпляр перед возвратом Это.

    Если __new __ () возвращает экземпляр cls, то метод __init __ () нового экземпляра будет вызван как __init __ (self [, …]), где self – это новый экземпляр, а остальные аргументы те же, что и для __new __ ().

    Если __new __ () не возвращает экземпляр cls, то метод __init __ () нового экземпляра не будет вызван.

    __new __ () предназначен в основном для того, чтобы подклассы неизменяемых типов (например, int, str или кортеж) настраивали создание экземпляра. Он также обычно переопределяется в пользовательских метаклассах, чтобы настроить создание классов.

    поэтому в ответ @mg. , первая не вызывает функцию __init__, а последняя вызывает функцию __init__ после вызова __new__.

     class MyMeta(type): def __new__(meta, cls, bases, attributes): print 'MyMeta.__new__' return type.__new__(meta, cls, bases, attributes) def __init__(clsobj, cls, bases, attributes): print 'MyMeta.__init__' class MyClass(object): __metaclass__ = MyMeta foo = 'bar' 

    Другой способ добиться такого же результата:

     cls = "MyClass" bases = () attributes = {'foo': 'bar'} MyClass = MyMeta(cls, bases, attributes) 

    MyMeta является вызываемым, поэтому Python будет использовать специальный метод «__call__».

    Python будет искать «__call__» в типе MyMeta (который является «типом» в нашем случае)

    «Для классов нового стиля неявные вызовы специальных методов гарантируются только корректно, если они определены по типу объекта, а не в словаре экземпляра объекта»,

    MyClass = MyMeta (…) интерпретируется как:

     my_meta_type = type(MyMeta) MyClass = my_meta_type.__call__(MyMeta, cls, bases, attributes) 

    Внутри типа .__ call __ () я представляю что-то вроде этого:

     MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes) meta_class = MyClass.__metaclass__ meta_class.__init__(MyClass, cls, bases, attributes) return MyClass 

    MyMeta .__ new __ () решит, как будет построен MyClass:

    type .__ new __ (meta, cls, base, attributes) установит правильный метакласс (который является MyMeta) для MyClass

    type (cls, base, attributes) будет устанавливать метакласс по умолчанию (который является типом) для MyClass

    Пожалуйста, обратитесь к аннотации ниже, надейтесь, что это поможет.

     class MetaCls(type): def __new__(cls, name, bases, dict): # return a new type named "name",this type has nothing # to do with MetaCls,and MetaCl.__init__ won't be invoked return type(name, bases, dict) class MetaCls(type): def __new__(cls, name, bases, dict): # return a new type named "name",the returned type # is an instance of cls,and cls here is "MetaCls", so # the next step can invoke MetaCls.__init__ return type.__new__(cls, name, bases, dict) 
     return type(name, bases, dict) 

    То, что вы получаете от этого, – это новый type , а не экземпляр MetaCls вообще. Следовательно, ваши методы, определенные в MetaCls (включая __init__ ), никогда не могут быть вызваны.

    type.__new__ будет вызван как часть создания этого нового типа, да, но значение cls в эту функцию, будет type а не MetaCls .

    Здесь все очень хорошо описано.

    Если вы не вернете правильный тип объекта, нет смысла определять настраиваемый метакласс.

    Python - лучший язык программирования в мире.