DynamicClassAttribute: Descriptors and Dynamic Access

Published on: August 30, 2026
Reading time: 2 minutes
Detailed close-up of yellow and white albino python scales, capturing texture and pattern.

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.

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.

External sources

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Close-up of vibrant JavaScript code featuring functions and syntax highlighting.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python UserList: Custom Sequences

    Learn Python UserList for custom mutable sequences with validation, normalization, mutation rules, copying, and predictable APIs.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python UserDict: Custom Mappings

    Learn Python UserDict for custom mappings with validation, normalization, composition, copying, and predictable mutation behavior.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Detailed close-up of yellow and white albino python scales, capturing texture and pattern.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.accumulate: Running Sums and State

    Learn Python itertools.accumulate for running sums, balances, records, custom state transitions, and lazy data pipelines.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.groupby: Group Sorted Data Correctly

    Learn Python itertools.groupby for ordered data, streaming aggregation, shared iterators, object keys, and correct grouping behavior.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: Risks of Changing Directories

    Learn Python contextlib.chdir, its global-state and concurrency risks, and when pathlib or subprocess cwd is the safer design.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026
    A person typing on a laptop with a Python programming book visible, capturing technology and learning.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python nullcontext: Optional Contexts

    Use Python nullcontext to unify optional files, locks, transactions, sessions, and borrowed resources without duplicate branches.

    Ler mais

    Tempo de leitura: 4 minutos
    30/08/2026