I have a certain class MyClass
with a class attribute SOMETHING
:
class MyClass(object):
SOMETHING = 12
I would like SOMETHING
to be enforced to meet a certain condition, e.g. SOMETHING < 100
.
How could I do that?
Ultimately, this class is meant to be subclassed by the user, e.g.:
class MySubClass(MyClass):
SOMETHING = 13
I have been looking into the class-property approaches outlined here, but they all seem to not play nicely with defining the property in the class
body.
For example:
class MyClassMeta(type):
_SOMETHING = 0
@property
def SOMETHING(cls):
return cls._SOMETHING
@SOMETHING.setter
def SOMETHING(cls, something):
if something < 100:
cls._SOMETHING = something
else:
raise ValueError('SOMETHING must be < 100')
class MyClass(object, metaclass=MyClassMeta):
# this is ignored
SOMETHING = 100
x = MyClass()
print(MyClass.SOMETHING)
# 0
print(type(x).SOMETHING)
# 0
However, if the attribute is accessed normally, e.g.:
MyClass.SOMETHING = 50
print(MyClass.SOMETHING)
# 50
print(type(x).SOMETHING)
# 50
it works fine, even with subclassing:
class MySubClass(MyClass):
SOMETHING = 40
y = MySubClass()
print(MySubClass.SOMETHING)
# 50
print(type(y).SOMETHING)
# 50
except that setting SOMETHING
in the subclass is also ignored.
So, how could I trigger the execution of the @SOMETHING.setter
code when SOMETHING
is defined in the body of the class
?
Use the following simple metaclass implementation to validate class specific attributes on declaration phase:
class MyClassMeta(type):
def __new__(cls, clsname, bases, clsdict):
if clsdict['SOMETHING'] >= 100: # validate specific attribute value
raise ValueError(f'{clsname}.SOMETHING should be less than 100')
return type.__new__(cls, clsname, bases, clsdict)
class MyClass(metaclass=MyClassMeta):
SOMETHING = 12
class MyChildClass(MyClass):
SOMETHING = 100
Running throws:
ValueError: MyChildClass.SOMETHING should be less than 100
https://docs.python.org/3/reference/datamodel.html#basic-customization