4

У меня есть класс Parent. Я хочу определить __new__ для Parent, так что он немного магии при создании экземпляра (почему, см. Сноску). Я также хочу, чтобы классы детей наследовали этот и другие классы, чтобы получить функции Parent. Parent__new__ вернет экземпляр подкласса базовых классов дочернего класса и класс Parent.Python множественное наследование: какой __new__ позвонить?

Это, как будет определен класс ребенок:

class Child(Parent, list): 
    pass 

Но теперь я не знаю, что __new__ позвонить в Parent «s __new__. Если я позвоню object.__new__, приведенный выше пример Child жалуется, что следует называть list.__new__. Но как бы Parent знал это? Я сделал это работа, так что петли через все __bases__ и вызывать каждый __new__ внутри try: блока:

class Parent(object): 
    def __new__(cls, *args, **kwargs): 
     # There is a special wrapper function for instantiating instances of children 
     # classes that passes in a 'bases' argument, which is the __bases__ of the 
     # Children class. 
     bases = kwargs.get('bases') 
     if bases: 
      cls = type('name', bases + (cls,), kwargs.get('attr', {})) 
      for base in cls.__mro__: 
       if base not in (cls, MyMainType): 
        try: 
         obj = base.__new__(cls) 
         break 
        except TypeError: 
         pass 
      return obj 
     return object.__new__(cls) 

Но это только выглядит как взломать. Наверняка, должен быть лучший способ сделать это?

Спасибо.

  • Причины я хочу использовать __new__ так я могу вернуть объект подкласса, который имеет некоторые динамические атрибуты (магию __int__ атрибутов и т.д.), присвоенные класс. I could have done this in __init__, но я не смог бы изменить self.__class__ в __init__, если новый класс имеет другую внутреннюю структуру, что в данном случае происходит из-за множественного наследования.
+0

У меня был ответ, но потом я понял, что полностью не понял ваш вопрос, поэтому я удалил его, а затем пересмотрел и отменил его. Я думаю, что новый ответ решает вашу проблему и будет работать. Я провел небольшое тестирование. – Omnifarious

+0

Вы отчетливо вписываетесь в метаклассическое программирование, как сложное, так и удивительное. Причина, по которой вы получаете ошибку с __new__, состоит в том, что 'object' и встроенные типы, такие как' list' и 'dict', а также объекты с' __slots__' имеют разные макеты памяти. Более глубокое понимание того, что вы пытаетесь выполнить, поможет многое. Вы также можете посмотреть на использование декоратора класса или функции в слоте __metaclass__. –

+0

Я не уверен, почему вам нужно будет изменить себя .__ class__, вы не упомянули об этом. И если вам нужно сделать сложную магию, как это в __new__, одно решение, которое часто намного проще, - это не делать этого вообще, а вместо этого использовать фабрику. –

ответ

4

Я думаю, что это поможет вам, что вы хотите:

return super(Parent, cls).__new__(cls, *args, **kwargs) 

и вам не нужен будет аргумент bases ключевого слова. Если я не ошибаюсь, и вы это намеренно делаете.

+0

Я думаю, что так оно и было. Я пробовал это раньше, к сожалению, у меня была другая ошибка в моем коде, которая мешала этому работать. Суперфункция - одна черта волшебной пули. –

+1

@MTsoul, Действительно. Честно говоря, я не знаю, почему это сработало, я просто подумал. :-) – Omnifarious

Смежные вопросы