Python: как сделать атрибут абстрактного класса со всеми соглашениями по именованию заглавными буквами и предупреждениями линтера - PullRequest
0 голосов
/ 26 марта 2020

У меня есть абстрактный базовый класс с атрибутом константного класса.

Как я могу заставить дочерний класс переопределить его?

Я хотел бы оставить все заглавные буквы Соглашение PEP8 для констант.


Пример кода

from abc import ABC


class BaseClass(ABC):
    """Some abstract base class."""

    # How do I force children to override this?
    CONST_CLASS_ATTR = "base"


class ChildClass(BaseClass):
    """Child class."""

    CONST_CLASS_ATTR = "child"


Потенциальные решения

Здесь уже есть очень похожий вопрос: Абстрактные атрибуты в Python

Однако все ответы кажутся обходными. Мне интересно, есть ли более простой способ?

Ответ: { ссылка }

Указывает использовать два декоратора: abstractmethod + property

  • Плюсы: Линтер сообщает мне, если дочерний класс не реализует CONST_CLASS_ATTR и не может создать экземпляр во время выполнения из-за его абстрактности
  • Минусы: Линтер (pylint) теперь жалуется invalid-name и я хотел бы, чтобы у констант было все соглашение о присвоении имен заглавными буквами
from abc import ABC, abstractmethod


class AnotherBaseClass(ABC):
    """Some abstract base class."""

    @abstractmethod
    @property
    def CONST_CLASS_ATTR(self) -> str:
        return "base"


class AnotherChildClass(AnotherBaseClass):
    """Child class."""

    @property
    def CONST_CLASS_ATTR(self) -> str:
        return "child"

Ответ: { ссылка }

Указывает использовать метод dunder __init_subclass__. Это лучше, так как мой линтер больше не жалуется, но он менее очевиден.

  • Плюсы: Линтер больше не жалуется на invalid-name и не может быть создан во время выполнения из-за повышения NotImplementedError
  • Минусы: Линтер больше не предупреждает, если дочерний класс не реализует CONST_CLASS_ATTR. Кроме того, это кажется мне многословным
from abc import ABC


class YetAnotherBaseClass(ABC):
    """Some abstract base class."""

    CONST_CLASS_ATTR: str

    @classmethod
    def __init_subclass__(cls):
        if not hasattr(cls, 'CONST_CLASS_ATTR'):
            raise NotImplementedError(
                f"Class {cls} lacks required CONST_CLASS_ATTR class attribute.")


class YetAnotherChildClass(YetAnotherBaseClass):
    """Child class."""

    CONST_CLASS_ATTR = "child"

Я использую Python 3,6

1 Ответ

1 голос
/ 26 марта 2020

Я думаю, что подход декоратора собственности является самым чистым. Просто тишина pylint:

@abstractmethod
@property
def CONST_CLASS_ATTR(self) -> str:  # pylint: disable=invalid-name
    return "base"

Это только отключит предупреждение для этого конкретного c метода и его переопределений.

...