Многократное наследование Python: какую __new__ вызывать? - PullRequest
4 голосов
/ 26 января 2010

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

Вот как будет определен дочерний класс:

class Child(Parent, list):
    pass

Но теперь я не знаю, как __new__ позвонить в Parent __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__ и т. Д.), Назначенные классу. Я мог бы сделать это в __init__, но я не смог бы изменить self.__class__ в __init__, если новый класс имеет другую внутреннюю структуру, что имеет место здесь из-за множественного наследования .

1 Ответ

4 голосов
/ 26 января 2010

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

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

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

...