Почему в этом сценарии создания подклассов вызывается неправильный метод? - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть две ситуации, которые кажутся похожими, но в одной ситуации методы вызываются так, как я ожидаю, а в другой нет.

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

class SuperOfAll(abc.ABC)
    @classmethod
    def method_one(cls, argument):
        """
        Uses class methods of subclasses.
        """
        cls.method_two(argument)
        # Some more things
        return "Done"

    @classmethod
    @abstractmethod
    def method_two(cls, argument):
        pass

    @classmethod
    @abstractmethod
    def method_three(cls, argument):
        pass

Тогда все разработчики являются подклассами одного из двух абстрактных вариантов:

class VariantOne(SuperOfAll):
    @classmethod
    def method_two(cls, argument):
        # do something
        return "Variant One"

class VariantTwo(SuperOfAll):
    @classmethod
    def method_two(cls, argument):
        # do something
        return "Variant Two"

Когда я реализую последний абстрактный метод в следующем классе,

class UsedByUser(VariantOne):
    @classmethod
    def method_three(cls, argument):
        # do something
        return "UsedByUser variant one"

, тогда все будет работать как ожидается, и method_three из UsedByUser будет вызван во время UsedByUser.method_one(argument).

Как только я введу дополнительный уровень подклассов, однако:

class ExtraLevel(SuperOfAll):
    @classmethod
    def method_one(cls, argument):
        value = SuperOfAll.method_one(argument)
        # do more
        return "Done"
class UsedByUserExtraLevel(ExtraLevel, VariantOne):
    @classmethod
    def method_three(cls, argument):
        # do something
        return "UsedByUser variant one"

Это не сработает то же самое, что и во время UsedByUserExtraLevel.method_one(argument) вызывается abstract method_two из SuperOfAll, который (очевидно) не реализован.

Почему существует разница в том, как метод имена разрешаются между этими двумя примерами? Почему вместо method_two метода VariantOne не вызывается, поскольку он не является абстрактным? Являются ли аннотации @abstractmethod значимыми только для предотвращения инстанцирования или они играют роль в разрешении этих методов?

...