Python:如何创建抽象类属性,使用全大写命名约定和linter警告

3
我有一个抽象基类,其中包含一个常量类属性。
如何强制子类覆盖它?
我想保持全部大写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中的抽象属性 然而,所有答案似乎都是变通方法。我想知道,是否有更简单的方法?
回答:https://dev59.com/U3E85IYBdhLWcg3whD7k#58321197 指示使用两个装饰器:abstractmethod + property 优点:Linter会提示我子类没有实现CONST_CLASS_ATTR,并且由于它是抽象的,无法在运行时实例化
缺点:Linter (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"


答案:https://dev59.com/U3E85IYBdhLWcg3whD7k#55544173的回答建议使用dunder方法__init_subclass__。这样做更好,因为我的linter不再抱怨,但它不够明显。
优点:Linter不再抱怨invalid-name,并且由于引发NotImplementedError而无法在运行时实例化。
缺点:如果子类未实现CONST_CLASS_ATTR,linters不再警告。此外,这对我来说似乎有些啰嗦。
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。

谢谢你发布这个问题,我已经寻找了一段时间了,很高兴看到这不仅是我的关注点:)这个问题绝对值得更多的关注,我个人感到惊讶的是它没有被代码检查工具考虑进去,因为使用大写字母命名常量是 PEP 规范的一部分。 - tikej
1个回答

2

我认为使用属性装饰器的方法是最干净的。只需将pylint静音:

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

这只会让这个特定的方法及其覆盖静默警告。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接