简体   繁体   中英

Python: how to make abstract class attribute, with all caps naming convention and linter warnings

I have an abstract base class, with a constant class attribute.

How can I force a child class to override it?

I would like to keep the all caps PEP8 convention for constants.


Sample Code

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"


Potential Solutions

There is a very similar question already on here: Abstract attributes in Python

However, all the answers seem to be workarounds. I am wondering, is there a simpler way?

Answer: https://stackoverflow.com/a/58321197/11163122

Instructs to use two decorators: abstractmethod + property

  • Pros: Linter informs me if child class doesn't implement CONST_CLASS_ATTR , and cannot instantiate at runtime due to it being abstract
  • Cons: Linter ( pylint ) now complains invalid-name , and I would like to keep the constants have all caps naming convention
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"

Answer: https://stackoverflow.com/a/55544173/11163122

Instructs to use the dunder method __init_subclass__ . This is better, as my linter no longer complains, but it's less obvious.

  • Pros: Linter no longer complains about invalid-name , and cannot instantiate at runtime due to raising a NotImplementedError
  • Cons: Linter no longer warns if child class doesn't implement CONST_CLASS_ATTR . Also, this seems verbose to me
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"

I am using Python 3.6

I think the property decorator approach is the cleanest. Just silence pylint:

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

This will only silence the warning for this specific method and its overrides.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM