types.DynamicClassAttribute is a specialized descriptor that behaves like a property on instances while allowing class-level access to be routed through the class’s metaclass __getattr__. This unusual behavior supports APIs where the same name needs different meanings on an instance and on the class.
The best-known use is related to Enum. Before using it directly, understand descriptors, properties, and metaclasses.
Basic behavior
from types import DynamicClassAttribute
class Item:
def __init__(self, value):
self._value = value
@DynamicClassAttribute
def value(self):
return self._value
print(Item(10).value)
On an instance, the descriptor behaves similarly to property.
Class-level access
When Item.value is requested, the descriptor raises AttributeError. A metaclass can then answer through __getattr__.
class Meta(type):
def __getattr__(cls, name):
if name == "value":
return "class-level value"
raise AttributeError(name)
class Item(metaclass=Meta):
@DynamicClassAttribute
def value(self):
return 42
print(Item().value)
print(Item.value)
Difference from property
A normal property accessed on the class usually returns the descriptor object. DynamicClassAttribute intentionally triggers the missing-attribute path at class level.
Descriptor protocol
Descriptors control access through __get__, __set__, and __delete__. Like property, this class supports getter, setter, and deleter methods.
Metaclass requirement
The dynamic class-level behavior requires __getattr__ on the metaclass. Defining an instance method named __getattr__ on the regular class does not handle missing attributes of the class object itself.
Why Enum needs this idea
Enum implementations distinguish member lookup, instance attributes, and names resolved on the enum class. A dynamic class attribute helps keep those namespaces separate.
Good use cases
- Frameworks with metaclass-managed namespaces.
- APIs with intentionally different class and instance semantics.
- Enum-like type systems.
- Advanced proxy and introspection infrastructure.
When to avoid it
Most applications are clearer with different names or explicit class methods. Dynamic resolution complicates autocomplete, documentation, static analysis, and debugging.
Static introspection
Normal getattr can execute dynamic lookup. Use inspect.getattr_static or inspect.getmembers_static to inspect the descriptor without invoking it.
import inspect
descriptor = inspect.getattr_static(Item, "value")
print(type(descriptor))
Typing concerns
Type checkers may not model metaclass-generated names perfectly. Keep public APIs simple and consider stubs, protocols, or overloads.
Common mistakes
- Placing
__getattr__on the class instead of the metaclass. - Expecting class access to return the descriptor.
- Creating recursion inside dynamic lookup.
- Using it where a normal property is sufficient.
- Ignoring documentation and introspection behavior.
Recommended practice
Limit this feature to infrastructure code, test both access paths, preserve useful AttributeError messages, and document the dual meaning. See the internal guides to the types module, Enums, and introspection.
Conclusion
DynamicClassAttribute combines instance-property behavior with dynamic class-level resolution. It is powerful for metaclass frameworks but should be used sparingly.







