(Sei que há perguntas semelhantes já respondidas, mas minha pergunta se concentra mais no motivo por trás da solução do que na solução em si).
Eu precisava de algo como uma "propriedade de classe" em Python e pesquisei em perguntas existentes. Algumas respostas oferecem uma solução alternativa, mas não consigo entender por que o Python desativou o encadeamento @classmethod
e @property
. Existe alguma explicação para isso?
Além disso, descobri que todas as soluções disponíveis atualmente têm limitações, listadas abaixo. As postagens que li incluem:
- Uma resposta que aponta que o encadeamento
@classmethod
e@property
foi desabilitado desde o Python 3.13 - Outra solução que define um descritor personalizado
classproperty
. Mas esta solução alternativa não impede modificações. Por exemplo, o código a seguir, derivado da resposta original, não gerará uma exceção quandox
houver tentativa de modificação.class classproperty(property): def __get__(self, owner_self, owner_cls): return self.fget(owner_cls) def __set__(self, instance, value): raise AttributeError("can't set attribute") class C(object): @classproperty def x(cls): return 1 print(C.x) C.x = 2 print(C.x) # Output: 2 # no exception raised # cannot prevent modification
- Uma solução é escrever a propriedade de classe na metaclasse. Este método impede com sucesso tentativas de modificação, mas com este método, o acesso às variáveis de classe só será possível via classe, não via instância.
class CMeta(type): @property def x(cls): return 1 class C(object, metaclass=CMeta): ... print(C.x) # C.x = 2 # AttributeError: property 'x' of 'CMeta' object has no setter # print(C().x) # AttributeError: 'C' object has no attribute 'x'
Então, existe uma maneira definitiva de resolver todos os problemas mencionados acima e permitir uma implementação de propriedade de classe que satisfaça as duas condições a seguir?
- Pode evitar tentativas de modificação
- Pode ser acessado tanto da classe quanto da instância
A propriedade Class foi descontinuada no Python 3.11 (com link para os problemas originais) porque foi descoberto que era impossível que uma cadeia de atributos decorados
@classmethod
com and@property
fosse vista pelo código de inspeção como uma instância deproperty
.Se você precisa que uma propriedade de classe funcione em uma instância, então uma personalizada
classproperty
é a melhor opção, mas para evitar modificações você pode substituir o__setattr__
método da metaclasse para que ele gere uma exceção se o atributo nomeado for considerado uma instância declassproperty
:Demonstração: https://ideone.com/4Ys77N