У меня есть две ситуации, которые кажутся похожими, но в одной ситуации методы вызываются так, как я ожидаю, а в другой нет.
Все классы подклассируют этот абстрактный суперкласс:
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
значимыми только для предотвращения инстанцирования или они играют роль в разрешении этих методов?