Подтвердить что ты не робот

"MetaClass", "__new__", "cls" и "super" - в чем именно механизм?

Я прочитал сообщения вроде этих:

Но почему-то я смутился. Многие путаницы вроде:

Когда и зачем мне нужно делать что-то вроде следующего?

# Refer link1
return super(MyType, cls).__new__(cls, name, bases, newattrs)

или

# Refer link2
return super(MetaSingleton, cls).__call__(*args, **kw)

или

# Refer link2
return type(self.__name__ + other.__name__, (self, other), {})

Как супер работает точно?

Что такое реестр классов и unregistry в link1 и как именно он работает? (Я думал, что это имеет какое-то отношение к singleton. Возможно, я ошибаюсь, будучи на фоне C. Мой стиль кодировки по-прежнему представляет собой смесь функционального и OO).

Каков поток создания экземпляра класса (подкласс, метакласс, супер, тип) и вызов метода (

metaclass->__new__, metaclass->__init__, super->__new__, subclass->__init__ inherited from metaclass

) с хорошо прокомментированным рабочим кодом (хотя первая ссылка довольно близка, но она не говорит о ключевом слове cls и супер (..) и реестре). Предпочтительно пример с множественным наследованием.

P.S.: Я сделал последнюю часть как код, потому что Stack форматирование переполнения конвертировало текст metaclass->__new__ to metaclass → новый

4b9b3361

Ответ 1

Хорошо, вы бросили в смесь немало концепций! Я собираюсь вытащить несколько конкретных вопросов, которые у вас есть.

В общем, понимание супер, MRO и metclasses сделано намного сложнее, потому что в этой сложной области было много изменений в последних версиях Python.

Собственная документация Python является очень хорошей ссылкой и полностью обновлена. Существует статья статья IBM developerWorks, которая прекрасно подходит для внедрения и использует более учебный подход, но обратите внимание, что ей пять лет, и много тратит много времени на подходы к метаклассам в старом стиле.

super - это доступ к суперклассам объекта. Это сложнее, чем (например) ключевое слово Java super, в основном из-за множественного наследования в Python. Поскольку Super Considered Harmful" объясняет, использование super() может привести к тому, что вы неявно используете цепочку суперклассов, порядок которой определяется Порядок разрешения метода (MRO).

Вы можете легко просмотреть MRO для класса, вызвав mro() в классе (а не в экземпляре). Обратите внимание, что метаклассы не находятся в иерархии суперклассов объекта.

Thomas 'описание метаклассов здесь превосходно:

Метакласс является классом класса. Как класс определяет, как экземпляр класса ведет себя, метакласса определяет поведение класса. Класс является экземпляром метакласса.

В примерах, которые вы приводите, вот что происходит:

  • Вызов __new__ пузырялся до следующего MRO. В этом случае super(MyType, cls) будет разрешено type; вызов type.__new__ позволяет Python завершите нормальный экземпляр шаги создания.

  • В этом примере используются метаклассы для обеспечения синглотона. Он переопределение __call__ в метакласса, чтобы всякий раз, когда класс экземпляр создается, он перехватывает это, и может обойти экземпляр создание, если уже есть (хранится в cls.instance). Заметка что переопределение __new__ в метакласс не будет достаточно хорош, потому что это называется только когда создавая класс. Переопределение __new__ в классе будет работать, однако.

  • Это показывает путь к динамическому создать класс. Вот он добавление имени класса к имени созданного класса и добавление его в иерархию классов тоже.

Я не совсем уверен, какой пример кода вы ищете, но здесь краткий, показывающий метаклассы, наследование и разрешение метода:

class MyMeta(type):
    def __new__(cls, name, bases, dct):
        print "meta: creating %s %s" % (name, bases)
        return type.__new__(cls, name, bases, dct)

    def meta_meth(cls):
        print "MyMeta.meta_meth"

    __repr__ = lambda c: c.__name__

class A(object):
    __metaclass__ = MyMeta
    def __init__(self):
        super(A, self).__init__()
        print "A init"

    def meth(self):
        print "A.meth"

class B(object):
    __metaclass__ = MyMeta
    def __init__(self):
        super(B, self).__init__()
        print "B init"

    def meth(self):
        print "B.meth"

class C(A, B):
    __metaclass__ = MyMeta
    def __init__(self):
        super(C, self).__init__()
        print "C init"

>>> c_obj = C()
meta: creating A (<type 'object'>,)
meta: creating B (<type 'object'>,)
meta: creating C (A, B)
B init
A init
C init
>>> c_obj.meth()
A.meth
>>> C.meta_meth()
MyMeta.meta_meth
>>> c_obj.meta_meth()
Traceback (most recent call last):
  File "mro.py", line 38, in <module>
    c_obj.meta_meth()
AttributeError: 'C' object has no attribute 'meta_meth'

Ответ 2

Здесь более прагматичный ответ.

Это редко имеет значение

Вот мой опыт за последние 7 лет программирования Python.

  • Класс имеет 1 или более суперклассов, образующих простую цепочку из моего класса в object.

  • Понятие "класс" определяется метаклассом с именем type. Я мог бы расширить концепцию "класса", но до сих пор она никогда не возникала на практике. Ни разу. type всегда поступает правильно.

  • Использование super отлично работает на практике. Это позволяет подклассу отложить до этого суперкласс. Это происходит в этих примерах метакласса, потому что они расширяют встроенный метакласс, type.

    Однако во всех ситуациях подкласса вы будете использовать super для расширения суперкласса.

Метаклассы

Проблема с метаклассом такова:

  • У каждого объекта есть ссылка на его определение типа или "класс".

  • A class сам является и объектом.

  • Поэтому объект типа class имеет ссылку на его тип или "класс". "Класс" "класса" является метаклассом.

Так как "класс" не является объектом времени выполнения С++, этого не происходит в С++. Это происходит в Java, Smalltalk и Python.

Метакласс определяет поведение объекта класса.

  • 90% вашего взаимодействия с классом - попросить класс создать новый объект.

  • В 10% случаев вы будете использовать методы класса или переменные класса ( "статические" в языках С++ или Java.)

Я нашел несколько вариантов использования для методов уровня класса. У меня почти нет вариантов использования для переменных класса. У меня никогда не было ситуации, чтобы изменить способ работы объекта.