0

Based on this question: Force child class to override parent's methods, my need is to set an attribute in the class that must be overridden by the child:

class Parent(ABC):
    property = None # this one must be defined

# this should fail
class Child(Parent):
    pass

Thanks!

Barmar
  • 741,623
  • 53
  • 500
  • 612
Jaime Escobar
  • 55
  • 1
  • 8

1 Answers1

7

You can use __init_subclass__ (which was intended to provide metaclass-like functionality via simple inheritance).

class Parent:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        if not hasattr(cls, 'property'):
            raise TypeError("Subclass must define class attribute 'property'")

class ChildThatWorks(Parent):
    property = 3

class ChildThatFails(Parent):
    pass

An interesting option is to pass property as an keyword argument, rather than an assignment in the body of the class statement.

class Parent:
    def __init_subclass__(cls, *, property, **kwargs):
        setattr(cls, 'property', property)

class ChildThatWorks(Parent, property=3):
    pass

class ChildThatFails(Parent):
    pass

ChildThatFails will produce the following traceback:

Traceback (most recent call last):
  File "/Users/chepner/tmp.py", line 8, in <module>
    class ChildThatFails(Parent):
TypeError: __init_subclass__() missing 1 required keyword-only argument: 'property'

The code is simpler, but you have less flexibility in how you handle the failure to provide the property value.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • I think there is also should be checking wether `property` is not equal to `None` (keeping in mind the code from the question). – machin Dec 09 '22 at 13:21
  • In this answer, `Parent` simply doesn't define `property` at all, rather than assigning it some sentinel value. – chepner Dec 09 '22 at 13:41