I have a base class from which I derive multiple subclasses.
Each subclass defines class constants, and I wish to enforce certain limitations on them.
For example:
class Base(object):
# define these in your sub-class, and make sure (NOM % DENOM == 0)
NOMINATOR = None
DENOMINATOR = None
class Subclass_good(Base):
NOMINATOR = 6
DENOMINATOR = 3
class Subclass_bad(Base):
NOMINATOR = 7
DENOMINATOR = 5
I want to be able to enforce the rule (NOM % DENOM == 0).
I currently do this with a class decorator:
def nom_denom_validator(cls):
assert(cls.NOMINATOR % cls.DENOMINATOR == 0)
return cls
# and decorate each subclass, e.g.:
@nom_denom_validator
class Subclass_another(Base):
NOMINATOR = 9
DENOMINATOR = 12
But I don't like the fact that I need to decorate each subclass (I have plenty). I'm interested whether this can be done by some manipulation on the Base class directly.
Any advice?
Ok, funny. I was thinking about it for a while, but only after posting the question - specifically when choosing tags, and adding "metaclass" there - did I realize I may have an answer myself.
So, submitted for review and future knowledge, here goes:
class Base_Metaclass(type):
def __new__(meta, classname, bases, class_dict):
new_type = type.__new__(meta, classname, bases, class_dict)
if not (new_type.NOMINATOR % new_type.DENOMINATOR) == 0:
raise Exception("Invalid subclass created - validation failed")
return new_type
# have Base and all its descendants be enforced:
class Base(object):
__metaclass__ = Base_Metaclass
# I must pass the validation myself, no None's anymore...
NOMINATOR = 1
DENOMINATOR = 1
And now all children should be auto-enforced.
You can do the checking in the base classes constructor
class Base(object):
# define these in your sub-class, and make sure (NOM % DENOM == 0)
NOMINATOR = None
DENOMINATOR = None
def __init__(self):
assert(self.NOMINATOR % self.DENOMINATOR == 0)
When you create an instance of Subclass_bad()
, you'll get AssertionError
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With