Недоразумение абстрактного базового класса Python 2.6, 3

Я не вижу то, что я ожидаю, когда я буду использовать ABCMeta и abstractmethod.

Это хорошо работает в python3:

from abc import ABCMeta, abstractmethod

class Super(metaclass=ABCMeta):
    @abstractmethod
    def method(self):
        pass

a = Super()
TypeError: Can't instantiate abstract class Super ...

И в 2,6:

class Super():
    __metaclass__ = ABCMeta
    @abstractmethod
    def method(self):
         pass

a = Super()
TypeError: Can't instantiate abstract class Super ...

Они оба также хорошо работают (я получаю ожидаемое исключение), если я происхожу Супер из объекта, в дополнение к ABCMeta.

Они оба "перестали работать" (никакое повышенное исключение), если я происхожу Супер из списка.

Я хочу, чтобы абстрактный базовый класс был списком, но кратким обзором и бетоном в sub классах.

Я делаю его неправильно, или разве я не должен хотеть это в Python?

9
задан Aaron 19 May 2010 в 23:32
поделиться

1 ответ

В сборке Super , как в ваших рабочих фрагментах, вы вызываете, когда выполняете Super () :

>>> Super.__init__
<slot wrapper '__init__' of 'object' objects>

Если Super наследуется от list , назовите его Superlist :

>>> Superlist.__init__
<slot wrapper '__init__' of 'list' objects>

Теперь абстрактные базовые классы предназначены для использования как классы mixin , чтобы быть умножить унаследованный от (чтобы получить возможности шаблона проектирования «Метод шаблона», которые может предложить ABC) вместе с конкретным классом, не делая результирующий потомок абстрактным. Итак, подумайте:

>>> class Listsuper(Super, list): pass
... 
>>> Listsuper.__init__
<slot wrapper '__init__' of 'list' objects>

Видите проблему? По правилам множественного наследования, вызов Listsuper () (который не может завершиться ошибкой только потому, что есть висящий абстрактный метод) запускает тот же код, что и вызов Superlist () (который вы бы хотели провалить). На практике этот код ( list .__ init __ ) не не возражает против висящих абстрактных методов - только объект .__ init __ . И исправление этого, вероятно, сломало бы код, который зависит от текущего поведения.

Предлагаемый обходной путь: если вам нужен абстрактный базовый класс, все его основы должны быть абстрактными.Итак, вместо того, чтобы иметь конкретный список среди ваших баз, используйте в качестве базы collections.MutableSequence , добавьте __ init __ , который составляет ._ list ] и реализовать абстрактные методы MutableSequence путем прямого делегирования в self._list . Не идеально, но и не так уж больно.

15
ответ дан 4 December 2019 в 12:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: