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 complainsinvalid-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 aNotImplementedError
- 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