I have a large amount of auto-generated classes in python that essentially represent enums for part of a communication protocol, they look like so
# definitions.py
class StatusCodes(ParamEnum):
Success = 1
Error = 2
UnexpectedAlpaca = 3
class AlpacaType(ParamEnum):
Fuzzy = 0
ReallyMean = 1
# etc etc etc
Defining things this way makes it easy for the auto-generator and also for humans to modify. The ParamEnum class provides all the functionality, get/setting, comparison, conversion and creation from the incoming network data and etc.
However, these classes require some extra meta-data. I do not want to add this into the source definition of each class though, as it makes it less readable and will break the autogenerator
At the moment I am doing it like this
# param_enum.py
class ParamEnum(object):
def __init__(self):
self.__class__._metadata = get_class_metadata(self.__class__)
however that strikes me as somewhat inefficient, since this will happen every time we instantiate one of these Enums (which happens often), not just on definition (the metadata does not change, so it only needs to be set once)
I tried added this to the bottom of the definition file, but ran into problems there too.
class StatusCodes(ParamEnum):
Success = 1
Error = 2
UnexpectedAlpaca = 3
for var in locals(): # or globals?
add_metadata(var)
#doesn't work because it is in the same file, modifying dict while iteratng
Is there a way in python of overriding/adding functionality to when the class is defined, that can be inherited to subclasses? Ideally I'd like something like
class ParamEnum(object):
def __when_class_defined__(cls):
add_metadata(cls)
Use a class decorator
def add_metadata(cls):
cls._metadata = get_class_metadata(cls)
return cls
@add_metadata
class StatusCodes(ParamEnum):
Success = 1
Error = 2
UnexpectedAlpaca = 3
What you want to do is in fact the very motivation to have decorators: The modification of a class or function after it has been created.
If you are unfamiliar with decorators, please read this (although it's a bit lengthy).
You could also use metaclasses, but they introduce more complexity than a decorator. If you want to avoid the additional decoration line @add_metadata
and you think it is redundant with respect to the specified subclass ParamEnum
, you could also make _metadata
a descriptor with lazy evaluation within the base class ParamEnum
.
class MetadataDescriptor(object):
def __get__(self, obj, cls):
if cls._metadata_value is None:
cls._metadata_value = get_class_metadata(cls)
return cls._metadata_value
class ParamEnum(object):
_metadata_value = None
_metadata = MetadataDescriptor()
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