"MetaClass", "__new__", "cls" и "super" - что это за механизм? - PullRequest
28 голосов
/ 28 декабря 2008

Я читал сообщения, подобные этим:

  1. Что такое метакласс в Python?
  2. Каковы ваши (конкретные) варианты использования метаклассов в Python?
  3. Супер Python отличный, но вы не можете его использовать

Но как-то я запутался. Многие путаницы, как:

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

# 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), {})

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

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

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

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

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

P.S .: Я сделал последнюю часть как код, потому что форматирование Stack Overflow преобразовывало текст metaclass->__new__ в метакласс -> new

Ответы [ 2 ]

21 голосов
/ 28 декабря 2008

ОК, вы добавили сюда множество идей! Я собираюсь вытащить несколько конкретных вопросов, которые у вас есть.

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

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

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

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

Томас 'описание мета-классов здесь отлично:

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

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

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

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

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

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

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'
9 голосов
/ 28 декабря 2008

Вот более прагматичный ответ.

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

  1. " Что такое метакласс в Python ". Итог, type - метакласс всех классов. У вас практически нет практического использования для этого.

    class X(object):
        pass
    type(X) == type
    
  2. " Каковы ваши (конкретные) варианты использования метаклассов в Python? ". Нижняя линия. None.

  3. " Супер Python отличный, но вы не можете его использовать ". Интересная заметка, но мало практического значения. Вам никогда не понадобится разрешать сложные сети с множественным наследованием. Легко предотвратить возникновение этой проблемы, используя дизайн explicity Strategy вместо множественного наследования.

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

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

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

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

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

Метаклассы

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

  • Каждый объект имеет ссылку на определение его типа или «класс».

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

  • Следовательно, объект типа class имеет ссылку на свой тип или «класс». «Класс» «класса» является метаклассом.

Поскольку «класс» не является объектом времени выполнения C ++, в C ++ этого не происходит. Это происходит в Java, Smalltalk и Python.

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

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

  • 10% времени, вы будете использовать методы класса или переменные класса («статические» в языке C ++ или Java).

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

...