types.DynamicClassAttribute é um descriptor especializado que se comporta como uma propriedade quando acessado por uma instância, mas permite que o acesso pela classe seja encaminhado ao __getattr__ da própria classe. Esse comportamento é incomum e foi criado para APIs em que um mesmo nome precisa ter significado diferente no nível da instância e no nível da classe.
O exemplo mais conhecido está relacionado a Enum. Antes de usar o recurso diretamente, é importante entender descriptors, propriedades e metaclasses.
Comportamento básico
from types import DynamicClassAttribute
class Item:
def __init__(self, valor):
self._valor = valor
@DynamicClassAttribute
def valor(self):
return self._valor
item = Item(10)
print(item.valor)
Na instância, o descriptor funciona de forma semelhante a property.
Acesso pela classe
Quando Item.valor é acessado, o descriptor levanta AttributeError. Isso permite que uma metaclass com __getattr__ forneça uma resposta dinâmica.
class Meta(type):
def __getattr__(cls, nome):
if nome == "valor":
return "valor calculado na classe"
raise AttributeError(nome)
class Item(metaclass=Meta):
@DynamicClassAttribute
def valor(self):
return 42
print(Item().valor)
print(Item.valor)
A instância retorna 42; a classe usa o fallback da metaclass.
Diferença para property
Uma property comum acessada pela classe normalmente devolve o próprio objeto descriptor. DynamicClassAttribute foi projetado para provocar o caminho de atributo ausente no nível da classe.
Descriptors e __get__
Descriptors controlam acesso por meio de métodos como __get__, __set__ e __delete__. DynamicClassAttribute encapsula esse protocolo e suporta getter, setter e deleter, assim como property.
class Registro:
def __init__(self):
self._codigo = "A1"
@DynamicClassAttribute
def codigo(self):
return self._codigo
@codigo.setter
def codigo(self, valor):
self._codigo = str(valor)
Uso com metaclasses
O recurso só mostra seu diferencial quando a classe usa uma metaclass capaz de responder dinamicamente. O método __getattr__ deve ser implementado na metaclass, não como método de instância da classe.
Por que Enum usa uma ideia semelhante
Enums precisam distinguir membros, atributos de instância e resolução de nomes no nível da classe. O mecanismo permite que nomes sejam tratados dinamicamente sem perder propriedades úteis nas instâncias.
Quando usar
- Frameworks com metaclasses e namespaces dinâmicos.
- APIs em que o mesmo nome tem semântica distinta na classe e na instância.
- Implementações inspiradas em Enum.
- Ferramentas de introspecção ou proxies de tipos.
Quando evitar
Na maioria das aplicações, nomes diferentes ou métodos de classe explícitos são mais claros. O recurso aumenta a complexidade de introspecção, autocompletar, documentação e análise estática. Não o use apenas para economizar um nome.
Introspecção
getattr(Classe, nome) pode executar o fallback dinâmico. Para inspecionar descriptors sem dispará-los, use inspect.getattr_static ou inspect.getmembers_static.
import inspect
descriptor = inspect.getattr_static(Item, "valor")
print(type(descriptor))
Tipagem
Type checkers podem não compreender completamente namespaces produzidos por metaclasses. Considere stubs, overloads ou protocolos e mantenha a API pública simples.
Erros comuns
- Implementar
__getattr__na classe em vez da metaclass. - Esperar que o acesso pela classe devolva o descriptor.
- Criar recursão dentro de
__getattr__. - Usar o mecanismo onde uma
propertynormal bastaria. - Ignorar ferramentas de introspecção e documentação.
Boas práticas
Restrinja o recurso a infraestrutura, teste acesso por classe e instância, preserve mensagens de AttributeError e documente claramente a semântica dupla. Leia também os guias internos sobre módulo types, Enums e introspecção.
Conclusão
DynamicClassAttribute combina comportamento de propriedade na instância com resolução dinâmica no nível da classe. É poderoso em frameworks baseados em metaclasses, mas deve ser usado com parcimônia devido à complexidade adicionada.







