As of Python 3.4, there is a descriptor called DynamicClassAttribute. The documentation states:
types.DynamicClassAttribute(fget=None, fset=None, fdel
What is a DynamicClassAttribute
A DynamicClassAttribute
is a descriptor that is similar to property
. Dynamic
is part of the name because you get different results based on whether you access it via the class or via the instance:
instance access is identical to property
and simply runs whatever method was decorated, returning its result
class access raises an AttributeError
; when this happens Python then searches every parent class (via the mro
) looking for that attribute -- when it doesn't find it, it calls the class' metaclass's __getattr__
for one last shot at finding the attribute. __getattr__
can, of course, do whatever it wants -- in the case of EnumMeta
__getattr__
looks in the class' _member_map_
to see if the requested attribute is there, and returns it if it is. As a side note: all that searching had a severe performance impact, which is why we ended up putting all members that did not have name conflicts with DynamicClassAttribute
s in the Enum class' __dict__
after all.
and how do I use it?
You use it just like you would property
-- the only difference is that you use it when creating a base class for other Enums. As an example, the Enum
from aenum
1 has three reserved names:
name
value
values
values
is there to support Enum members with multiple values. That class is effectively:
class Enum(metaclass=EnumMeta):
@DynamicClassAttribute
def name(self):
return self._name_
@DynamicClassAttribute
def value(self):
return self._value_
@DynamicClassAttribute
def values(self):
return self._values_
and now any aenum.Enum
can have a values
member without messing up Enum.
.
1 Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.