Многократное наследование Python: что плохого в том, чтобы делать это динамически? - PullRequest
0 голосов
/ 08 января 2010

На основании этого ответа о том, как __new__ и __init__ должны работать в Python,

Я написал этот код для динамического определения и создания нового класса и объекта.

class A(object):
    def __new__(cls):
      class C(cls, B):
          pass
      self = C()
      return self

    def foo(self):
      print 'foo'

class B(object):
    def bar(self):
      print 'bar'

a = A()
a.foo()
a.bar()

По сути, поскольку __new__ из A возвращает динамически созданный C, который наследует A и B, он должен иметь атрибут bar.

Почему C не имеет атрибут bar?

Ответы [ 3 ]

7 голосов
/ 08 января 2010

Поскольку в вопросе нет актуального вопроса , я буду понимать его буквально:

Что не так делать динамически?
Ну, он практически нечитабелен, чрезвычайно непрозрачен и неочевиден для пользователя вашего кода (включая вас через месяц: P).

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

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

Еще один взгляд на вопрос:
Что не так делать динамически?
В вашей текущей реализации это выдает ошибку «превышена максимальная глубина рекурсии». Это происходит потому, что A.__new__ вызывает себя изнутри себя бесконечно (поскольку он наследует от себя и от B).

10: Внутри A.__new__ для "cls" установлено значение <class '.A'>. Внутри конструктора вы определяете класс C, который наследуется от cls (который на самом деле A) и другого класса B. При создании экземпляра C вызывается его __new__. Поскольку он не определяет свой собственный __new__, вызывается его базовый класс '__new__. Базовый класс, как оказалось, A.
20: GOTO 10

7 голосов
/ 08 января 2010

Разрешить бесконечная рекурсия:

class A(object):
  def __new__(cls):
    class C(cls, B):
      pass
    self = object.__new__(C)
    return self

(Спасибо balpha за указание на актуальный вопрос)

3 голосов
/ 08 января 2010

Если ваш вопрос «Как мне это сделать» & ndash; это работает:

class A(object):
    @classmethod
    def get_with_B(cls):
      class C(B, cls):
        pass

      return C()

    def foo(self):
      print 'foo'

class B(object):
    def bar(self):
      print 'bar'

a = A.get_with_B()
a.foo()
a.bar()

Если ваш вопрос «Почему это не работает» & ndash; это потому, что вы сталкиваетесь с бесконечной рекурсией при вызове C(), что приводит к вызову A.__new__, который снова вызывает C() и т. д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...