Eu tenho uma classe com dois métodos de classe (usando a função classmethod ()) para obter e definir o que é essencialmente uma variável estática. Tentei usar a função property () com eles, mas isso resultou em um erro. Consegui reproduzir o erro com o seguinte no intérprete:
class Foo(object):
_var = 5
@classmethod
def getvar(cls):
return cls._var
@classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
Eu posso demonstrar os métodos de classe, mas eles não funcionam como propriedades:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
É possível usar a função property () com funções decoradas com método de classe?
class Foo(metaclass=...)
sintaxe.Lendo as notas de versão do Python 2.2 , acho o seguinte.
NOTA: O método abaixo, na verdade, não funciona para setters, apenas getters.
Portanto, acredito que a solução prescrita é criar um ClassProperty como uma subclasse de propriedade.
No entanto, os setters realmente não funcionam:
foo._var
permanecer inalterado, você simplesmente substituiu a propriedade por um novo valor.Você também pode usar
ClassProperty
como decorador:fonte
self.fget(owner)
e remove a necessidade de usar um@classmethod
aqui? (é isso queclassmethod
faz , traduzir.__get__(instance, owner)(*args, **kwargs)
parafunction(owner, *args, **kwargs)
chamadas, por meio de um intermediário; as propriedades não precisam do intermediário).foo.var = 3
atribuição não passa pela propriedade e, em vez disso, simplesmente substituiu o objeto de propriedade porfoo
um número inteiro. Se você adicionouassert isinstance(foo.__dict__['var'], ClassProperty)
chamadas entre suas asserções, verá que a falha após afoo.var = 3
execução.instance.attr
,instance.attr = value
edel instance.attr
todos se ligam o descritor será encontrado natype(instance)
, mas enquantoclassobj.attr
se liga,classobj.attr = value
edel classobj.attr
que não e em vez disso substituir ou eliminar o próprio objeto descritor). Você precisa de uma metaclasse para oferecer suporte à configuração e exclusão (tornando a classe objeto a instância e a metaclasse o tipo).Espero que esse
@classproperty
decorador simples e de leitura simples ajude alguém a procurar propriedades de classe.fonte
class D(C): x = 2; assert D.x == 2
.format
como"{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
:(x
acesso por10
. Eu gosto dessa abordagem porque é elegante e simples, mas soa como um antipadrão__set__
que gera umValueError
para impedir a substituição.Não.
No entanto, um método de classe é simplesmente um método vinculado (uma função parcial) em uma classe acessível a partir de instâncias dessa classe.
Como a instância é uma função da classe e você pode derivá-la, você pode obter o comportamento desejado de uma propriedade de classe com
property
:Este código pode ser usado para testar - ele deve passar sem gerar erros:
E observe que não precisávamos de metaclasses - e você não acessa diretamente uma metaclasse através das instâncias de suas classes.
escrevendo um
@classproperty
decoradorVocê pode realmente criar um
classproperty
decorador em apenas algumas linhas de código subclassificandoproperty
(ele é implementado em C, mas você pode ver o equivalente em Python aqui ):Trate o decorador como se fosse um método de classe combinado com a propriedade:
E esse código deve funcionar sem erros:
Mas não tenho certeza de quão bem aconselhado isso seria. Um artigo antigo de lista de discussão sugere que não deve funcionar.
Colocando a propriedade para trabalhar na classe:
A desvantagem do exposto acima é que a "propriedade de classe" não é acessível a partir da classe, porque simplesmente substitui o descritor de dados da classe
__dict__
.No entanto, podemos substituir isso por uma propriedade definida na metaclasse
__dict__
. Por exemplo:E então uma instância de classe da metaclasse pode ter uma propriedade que acessa a propriedade da classe usando o princípio já demonstrado nas seções anteriores:
E agora vemos tanto a instância
e a classe
tenha acesso à propriedade da classe
fonte
Python 3!
Pergunta antiga, muitos pontos de vista, extremamente necessitados de uma maneira única de Python 3.
Felizmente, é fácil com o
metaclass
kwarg:Então,
>>> Foo.var
fonte
Foo
é uma instância de sua metaclasse e@property
pode ser usada para seus métodos, assim como para as instâncias deFoo
.Foo.__new__
. Embora nesse ponto possa valer a pena usar getattribute ou questionar se fingir que um recurso de linguagem existe é realmente a abordagem que você deseja adotar.Não há uma maneira razoável de fazer esse sistema de "propriedade de classe" funcionar em Python.
Aqui está uma maneira irracional de fazê-lo funcionar. Você certamente pode torná-lo mais transparente com quantidades crescentes de magia de metaclasse.
O nó da questão é que as propriedades são o que Python chama de "descritores". Não há uma maneira curta e fácil de explicar como esse tipo de metaprogramação funciona; portanto, devo apontar o descritor como .
Você só precisa entender esse tipo de coisa se estiver implementando uma estrutura bastante avançada. Como uma persistência transparente de objeto ou sistema RPC ou um tipo de linguagem específica de domínio.
No entanto, em um comentário a uma resposta anterior, você diz que
Parece-me que o que você realmente deseja é um padrão de design do Observer .
fonte
A configuração apenas na meta classe não ajuda se você deseja acessar a propriedade da classe por meio de um objeto instanciado; nesse caso, você também precisa instalar uma propriedade normal no objeto (que é despachada para a propriedade da classe). Eu acho que o seguinte é um pouco mais claro:
fonte
Metade de uma solução, __set__ na classe, ainda não funciona. A solução é uma classe de propriedade customizada implementando uma propriedade e um staticmethod
fonte
Você tem acesso a pelo menos uma instância da classe? Posso pensar em uma maneira de fazer isso:
fonte
Faça uma tentativa, ele faz o trabalho sem precisar alterar / adicionar muito código existente.
A
property
função precisa de doiscallable
argumentos. dê a eles wrappers lambda (que passam a instância como seu primeiro argumento) e está tudo bem.fonte
Aqui está uma solução que deve funcionar tanto para acesso via classe quanto para acesso através de uma instância que usa uma metaclasse.
Isso também funciona com um setter definido na metaclasse.
fonte
Depois de pesquisar lugares diferentes, encontrei um método para definir uma propriedade de classe válida com Python 2 e 3.
Espero que isso possa ajudar alguém :)
fonte
Aqui está a minha sugestão. Não use métodos de classe.
Seriamente.
Qual o motivo do uso de métodos de classe neste caso? Por que não ter um objeto comum de uma classe comum?
Se você simplesmente deseja alterar o valor, uma propriedade não é realmente muito útil, é? Basta definir o valor do atributo e concluir com ele.
Uma propriedade só deve ser usada se houver algo a ocultar - algo que pode mudar em uma implementação futura.
Talvez o seu exemplo seja muito simples e exista algum cálculo infernal que você tenha deixado de fazer. Mas não parece que a propriedade agregue um valor significativo.
As técnicas de "privacidade" influenciadas por Java (no Python, nomes de atributos que começam com _) não são realmente muito úteis. Privado de quem? O ponto privado é um pouco nebuloso quando você tem a fonte (como você faz no Python.)
Os getters e setters do estilo EJB influenciados por Java (geralmente feitos como propriedades em Python) estão lá para facilitar a introspecção primitiva do Java, bem como para passar o agrupamento com o compilador de linguagem estática. Todos esses getters e setters não são tão úteis em Python.
fonte