É possível ter variáveis de classe estática ou métodos em Python? Qual sintaxe é necessária para fazer isso?
Variáveis declaradas dentro da definição de classe, mas não dentro de um método, são variáveis de classe ou estáticas:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Como o @ millerdev aponta, isso cria uma i
variável no nível da classe , mas é diferente de qualquer i
variável no nível da instância , então você pode ter
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Isso é diferente de C ++ e Java, mas não tão diferente de C #, onde um membro estático não pode ser acessado usando uma referência a uma instância.
Veja o que o tutorial do Python tem a dizer sobre o assunto de classes e objetos de classe .
@ Steve Johnson já respondeu sobre métodos estáticos , também documentados em "Funções internas " na Referência da biblioteca do Python .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
O @beidy recomenda classmethod s sobre staticmethod, pois o método recebe o tipo de classe como o primeiro argumento, mas ainda estou um pouco confuso sobre as vantagens dessa abordagem sobre o staticmethod. Se você também, provavelmente não importa.
@classmethod
mais de@staticmethod
AFAIK é que você sempre obter o nome da classe do método foi invocado, mesmo que seja uma subclasse. Um método estático não possui essas informações, portanto, não pode chamar um método substituído, por exemplo.const.py
comPI = 3.14
e você pode importá-lo em qualquer lugar.from const import PI
i = 3
é uma variável estática, é um atributo de classe e, como é distinto de um atributo no nível da instância , não se comporta como uma variável estática em outros idiomas. Veja a resposta de millerdev , a resposta de Yann , e minha resposta abaixo.i
i
(variável estática) estará na memória, mesmo que eu crie centenas de instâncias dessa classe?@Blair Conrad disse que variáveis estáticas declaradas dentro da definição de classe, mas não dentro de um método, são variáveis de classe ou "estáticas":
Há algumas pegadinhas aqui. Continuando a partir do exemplo acima:
Observe como a variável de instância
t.i
ficou fora de sincronia com a variável de classe "estática" quando o atributoi
foi definido diretamentet
. Isso ocorre porquei
foi ligado novamente not
espaço para nome, que é diferente doTest
espaço para nome. Se você deseja alterar o valor de uma variável "estática", altere-a no escopo (ou objeto) em que foi originalmente definida. Coloquei "estático" entre aspas porque o Python realmente não tem variáveis estáticas no sentido em que C ++ e Java o fazem.Embora não diga nada específico sobre variáveis ou métodos estáticos, o tutorial do Python possui algumas informações relevantes sobre classes e objetos de classe .
@ Steve Johnson também respondeu sobre métodos estáticos, também documentados em "Funções internas" na Referência da biblioteca do Python.
@beid também mencionou classmethod, que é semelhante ao staticmethod. O primeiro argumento de um método de classe é o objeto de classe. Exemplo:
fonte
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Agora você pode fazerx = Test()
,x.i = 12
,assert x.i == Test.i
.Métodos estáticos e de classe
Como as outras respostas observaram, os métodos estáticos e de classe são facilmente realizados usando os decoradores internos:
Como sempre, o primeiro argumento para
MyMethod()
é vinculado ao objeto de instância da classe. Por outro lado, o primeiro argumento paraMyClassMethod()
é vinculado ao próprio objeto de classe (por exemplo, neste casoTest
). PoisMyStaticMethod()
, nenhum dos argumentos é vinculado e ter argumentos é opcional."Variáveis estáticas"
No entanto, implementar "variáveis estáticas" (bem, variáveis estáticas mutáveis , de qualquer forma, se isso não for uma contradição em termos ...) não é tão simples. Como millerdev apontou em sua resposta , o problema é que os atributos de classe do Python não são verdadeiramente "variáveis estáticas". Considerar:
Isso ocorre porque a linha
x.i = 12
adicionou um novo atributo de instânciai
aox
invés de alterar o valor do atributo deTest
classei
.O comportamento parcial esperado da variável estática, ou seja, a sincronização do atributo entre várias instâncias (mas não com a própria classe; consulte "pegadinha" abaixo), pode ser alcançado transformando o atributo da classe em uma propriedade:
Agora você pode fazer:
A variável estática agora permanecerá sincronizada entre todas as instâncias de classe .
(NOTA: Ou seja, a menos que uma instância de classe decida definir sua própria versão do
_i
! Mas se alguém decide fazer ISSO, ele merece o que recebe, não é ???)Observe que tecnicamente falando,
i
ainda não é uma 'variável estática'; é umproperty
, que é um tipo especial de descritor. No entanto, oproperty
comportamento agora é equivalente a uma variável estática (mutável) sincronizada em todas as instâncias de classe."Variáveis estáticas" imutáveis
Para comportamento variável estático imutável, simplesmente omita o
property
setter:Agora, tentar definir o
i
atributo de instância retornará umAttributeError
:Um Gotcha para estar ciente de
Observe que os métodos acima funcionam apenas com instâncias da sua classe - eles não funcionarão ao usar a própria classe . Então, por exemplo:
A linha
assert Test.i == x.i
produz um erro, porque oi
atributoTest
ex
são dois objetos diferentes.Muitas pessoas vão achar isso surpreendente. No entanto, não deveria ser. Se voltarmos e inspecionarmos nossa
Test
definição de classe (a segunda versão), tomaremos nota desta linha:Claramente, o membro
i
deTest
deve ser umproperty
objeto, que é o tipo de objeto retornado daproperty
função.Se você acha que o exposto acima é confuso, é provável que ainda pense nisso da perspectiva de outras linguagens (por exemplo, Java ou c ++). Você deve estudar o
property
objeto, sobre a ordem em que os atributos do Python são retornados, o protocolo do descritor e a ordem de resolução do método (MRO).Apresento uma solução para o 'pegadinha' acima; no entanto, eu sugeriria - enfaticamente - que você não tente fazer algo como o seguinte até - no mínimo - entender completamente o porquê de
assert Test.i = x.i
causar um erro.Variáveis estáticas reais e reais -
Test.i == x.i
Apresento a solução (Python 3) abaixo apenas para fins informativos. Não estou endossando-o como uma "boa solução". Eu tenho minhas dúvidas sobre se emular o comportamento da variável estática de outras linguagens no Python é realmente necessário. No entanto, independentemente de ser realmente útil, o abaixo deve ajudar a entender melhor como o Python funciona.
UPDATE: esta tentativa é realmente bastante terrível ; se você insistir em fazer algo assim (dica: por favor, não; Python é uma linguagem muito elegante e faz com que ela se comporte como outra linguagem não é necessária), use o código na resposta de Ethan Furman .
Emulando o comportamento da variável estática de outros idiomas usando uma metaclasse
Uma metaclasse é a classe de uma classe. A metaclasse padrão para todas as classes no Python (ou seja, as classes de "novo estilo" após o Python 2.3, acredito) é
type
. Por exemplo:No entanto, você pode definir sua própria metaclasse assim:
E aplique-o à sua própria classe como esta (somente Python 3):
Abaixo está uma metaclasse que eu criei que tenta emular o comportamento da "variável estática" de outras linguagens. Basicamente, ele substitui o getter, setter e deleter padrão por versões que verificam se o atributo solicitado é uma "variável estática".
Um catálogo das "variáveis estáticas" é armazenado no
StaticVarMeta.statics
atributo Todas as solicitações de atributo são inicialmente tentadas a serem resolvidas usando uma ordem de resolução substituta. Eu chamei isso de "ordem de resolução estática" ou "SRO". Isso é feito procurando o atributo solicitado no conjunto de "variáveis estáticas" para uma determinada classe (ou suas classes pai). Se o atributo não aparecer no "SRO", a classe retornará ao comportamento padrão de obter / definir / excluir do atributo padrão (ou seja, "MRO").fonte
Test
(antes de usá-lo para instanciar instâncias) como estando no domínio da metaprogramação? Por exemplo, você altera o comportamento da classe fazendoTest.i = 0
(aqui você simplesmente destrói completamente o objeto de propriedade). Eu acho que o "mecanismo de propriedade" entra em ação apenas no acesso à propriedade em instâncias de uma classe (a menos que você altere o comportamento subjacente usando uma meta-classe como intermediária, talvez). Btw, por favor terminar esta resposta :-)Você também pode adicionar variáveis de classe às classes em tempo real
E instâncias de classe podem alterar variáveis de classe
fonte
Pessoalmente, usaria um método de classe sempre que precisasse de um método estático. Principalmente porque recebo a classe como argumento.
ou use um decorador
Para propriedades estáticas .. É hora de procurar alguma definição em python. A variável sempre pode mudar. Existem dois tipos deles mutáveis e imutáveis. Além disso, existem atributos de classe e atributos de instância. Nada como atributos estáticos no sentido de java & c ++
Por que usar o método estático no sentido pitônico, se não tem nenhuma relação com a classe! Se eu fosse você, usaria o método class ou definiria o método independentemente da classe.
fonte
Uma coisa especial a ser observada sobre propriedades estáticas e propriedades da instância, mostradas no exemplo abaixo:
Isso significa que, antes de atribuir o valor à propriedade da instância, se tentarmos acessar a propriedade através da instância, o valor estático será usado. Cada propriedade declarada na classe python sempre possui um slot estático na memória .
fonte
Métodos estáticos em python são chamados classmethod s. Dê uma olhada no código a seguir
Observe que quando chamamos o método myInstanceMethod , obtemos um erro. Isso ocorre porque requer que o método seja chamado em uma instância desta classe. O método myStaticMethod é definido como um método de classe usando o decorador @classmethod .
Apenas para brincadeiras e risadinhas, poderíamos chamar myInstanceMethod na classe passando uma instância da classe, assim:
fonte
@staticmethod
;@classmethod
é (obviamente) para métodos de classe (que se destinam principalmente ao uso como construtores alternativos, mas podem servir como uma pinça como métodos estáticos que recebem uma referência à classe pela qual foram chamados).Ao definir alguma variável de membro fora de qualquer método de membro, a variável pode ser estática ou não estática, dependendo de como a variável é expressa.
Por exemplo:
Os resultados são
fonte
É possível ter
static
variáveis de classe, mas provavelmente não vale o esforço.Aqui está uma prova de conceito escrita em Python 3 - se algum detalhe exato estiver errado, o código poderá ser ajustado para corresponder exatamente ao que você quer dizer com
static variable
:e em uso:
e alguns testes:
fonte
Você também pode fazer com que uma classe seja estática usando a metaclasse.
Então, sempre que por acidente você tentar inicializar o MyClass, receberá um StaticClassError.
fonte
__new__
de seus pais ...Um ponto muito interessante sobre a pesquisa de atributos do Python é que ele pode ser usado para criar " variáveis virtuais ":
Normalmente, não há atribuições para elas depois que elas são criadas. Observe que a pesquisa usa
self
porque, emboralabel
seja estático no sentido de não estar associado a uma instância específica , o valor ainda depende da instância (classe da).fonte
Em relação a esta resposta , para uma variável estática constante , você pode usar um descritor. Aqui está um exemplo:
resultando em ...
Você sempre pode gerar uma exceção se ignorar silenciosamente o valor da configuração (
pass
acima) não é o seu problema. Se você estiver procurando por uma variável de classe estática no estilo C ++, Java:Veja esta resposta e o HOWTO da documentação oficial para obter mais informações sobre descritores.
fonte
@property
, que é o mesmo que usar um descritor, mas é muito menos código.Absolutamente sim, o Python por si só não tem nenhum membro de dados estático explicitamente, mas podemos fazê-lo
resultado
explicação
fonte
Sim, definitivamente é possível escrever variáveis e métodos estáticos em python.
Variáveis estáticas: a variável declarada no nível da classe é chamada de variável estática, que pode ser acessada diretamente usando o nome da classe.
Variáveis de instância: variáveis relacionadas e acessadas por instância de uma classe são variáveis de instância.
Métodos estáticos: Semelhante às variáveis, os métodos estáticos podem ser acessados diretamente usando a classe Name. Não há necessidade de criar uma instância.
Mas lembre-se, um método estático não pode chamar um método não estático em python.
fonte
Para evitar qualquer confusão em potencial, gostaria de contrastar variáveis estáticas e objetos imutáveis.
Alguns tipos de objetos primitivos, como números inteiros, flutuantes, strings e toques, são imutáveis no Python. Isso significa que o objeto referido por um determinado nome não pode ser alterado se for de um dos tipos de objeto mencionados acima. O nome pode ser reatribuído para um objeto diferente, mas o próprio objeto não pode ser alterado.
Tornar uma variável estática leva isso um passo adiante, impedindo que o nome da variável aponte para qualquer objeto, exceto para o qual ele aponta atualmente. (Nota: este é um conceito geral de software e não é específico para o Python; consulte as postagens de outras pessoas para obter informações sobre a implementação de estática no Python).
fonte
A melhor maneira que encontrei é usar outra classe. Você pode criar um objeto e usá-lo em outros objetos.
Com o exemplo acima, criei uma classe chamada
staticFlag
.Esta classe deve apresentar a var estática
__success
(Var estática privada).tryIt
classe representou a classe regular que precisamos usar.Agora eu criei um objeto para uma bandeira (
staticFlag
). Este sinalizador será enviado como referência a todos os objetos regulares.Todos esses objetos estão sendo adicionados à lista
tryArr
.Resultados deste script:
fonte
Variáveis estáticas na classe factory python3.6
Para quem usa uma fábrica de classes com python3.6 e superior, use a
nonlocal
palavra-chave para adicioná-la ao escopo / contexto da classe que está sendo criada da seguinte forma:fonte
hasattr(SomeClass, 'x')
éFalse
. duvido que seja isso que alguém queira dizer com uma variável estática.some_var
imutável e estaticamente definido, ou não é? O que o acesso externo ao getter tem a ver com uma variável ser estática ou não? Eu tenho tantas perguntas agora. adoraria ouvir algumas respostas quando chegar a hora.some_var
acima não é um membro da classe. No Python, todos os membros da classe podem ser acessados de fora da classe.nonlocal
teclado "esbarra" no escopo da variável. O escopo de uma definição de corpo de classe é independente do escopo em que você se encontra, quando você diznonlocal some_var
que está apenas criando uma referência de nome não local (leia-se: NÃO no escopo de definição de classe) para outro objeto nomeado. Portanto, ele não é anexado à definição de classe porque não está no escopo do corpo da classe.Então isso é provavelmente um truque, mas eu tenho usado
eval(str)
para obter um objeto estático, como uma contradição, no python 3.Há um arquivo Records.py que não possui nada além de
class
objetos definidos com métodos e construtores estáticos que salvam alguns argumentos. Em seguida, de outro arquivo .py,import Records
eu preciso selecionar dinamicamente cada objeto e instancia-lo sob demanda, de acordo com o tipo de dados que está sendo lido.Então, onde
object_name = 'RecordOne'
ou o nome da classe, eu chamocur_type = eval(object_name)
e, em seguida, instancia-lo?cur_inst = cur_type(args)
No entanto, antes de instanciar, você pode chamar métodos estáticos,cur_type.getName()
por exemplo, como a implementação abstrata da classe base ou qualquer que seja o objetivo. No entanto, no back-end, provavelmente é instanciado em python e não é realmente estático, porque eval está retornando um objeto .... que deve ter sido instanciado ... que fornece um comportamento estático.fonte
Você pode usar uma lista ou um dicionário para obter "comportamento estático" entre instâncias.
fonte
Se você está tentando compartilhar uma variável estática para, por exemplo, aumentá-la em outras instâncias, algo como este script funciona bem:
fonte