Estou me ensinando Python e minha lição mais recente foi que Python não é Java e, portanto, passei um tempo transformando todos os meus métodos de classe em funções.
Agora percebo que não preciso usar métodos de classe para o que faria com static
métodos em Java, mas agora não tenho certeza de quando os usaria. Todo o conselho que posso encontrar sobre os métodos da classe Python é da mesma maneira que novatos como eu devem ficar longe deles, e a documentação padrão é a mais opaca quando os discutimos.
Alguém tem um bom exemplo de uso de um método Class em Python ou pelo menos alguém pode me dizer quando os métodos Class podem ser sensatamente usados?
fonte
obj.cls_mthd(...)
outype(obj).cls_mthd(...)
?Métodos de fábrica (construtores alternativos) são de fato um exemplo clássico de métodos de classe.
Basicamente, os métodos de classe são adequados sempre que você deseja ter um método que naturalmente se encaixe no espaço de nomes da classe, mas não está associado a uma instância específica da classe.
Como exemplo, no excelente módulo unipath :
Diretório atual
Path.cwd()
Path("/tmp/my_temp_dir")
,. Este é um método de classe..chdir()
Como o diretório atual é amplo para o processo, o
cwd
método não possui uma instância específica à qual deve ser associado. No entanto, alterar ocwd
diretório de uma determinadaPath
instância deve realmente ser um método de instância.Hmmm ... como
Path.cwd()
realmente retorna umaPath
instância, acho que poderia ser considerado um método de fábrica ...fonte
Pense desta maneira: os métodos normais são úteis para ocultar os detalhes da expedição: você pode digitar
myobj.foo()
sem se preocupar se ofoo()
método é implementado pelamyobj
classe do objeto ou por uma de suas classes pai. Os métodos de classe são exatamente análogos a isso, mas com o objeto de classe: eles permitem que você chameMyClass.foo()
sem ter que se preocupar sefoo()
é implementado especialmenteMyClass
porque precisava de sua própria versão especializada ou se está permitindo que sua classe pai lide com a chamada.Os métodos de classe são essenciais quando você está configurando ou computando antes da criação de uma instância real, porque até que a instância exista, você obviamente não poderá usar a instância como o ponto de despacho para as chamadas do método. Um bom exemplo pode ser visualizado no código-fonte SQLAlchemy; dê uma olhada no
dbapi()
método de classe no seguinte link:https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47
Você pode ver que o
dbapi()
método que um back-end do banco de dados usa para importar a biblioteca de banco de dados específica do fornecedor necessária sob demanda, é um método de classe porque ele precisa ser executado antes que as instâncias de uma determinada conexão com o banco de dados sejam criadas - mas não pode seja uma função simples ou estática, porque eles desejam chamar outros métodos de suporte que precisem ser escritos de maneira mais específica nas subclasses do que na classe pai. E se você despacha para uma função ou classe estática, "esquece" e perde o conhecimento sobre qual classe está inicializando.fonte
Recentemente, eu queria uma classe de log muito leve que produzisse quantidades variáveis de saída, dependendo do nível de log que poderia ser definido programaticamente. Mas eu não queria instanciar a classe toda vez que desejava gerar uma mensagem de depuração, erro ou aviso. Mas eu também queria encapsular o funcionamento desse recurso de registro e torná-lo reutilizável sem a declaração de quaisquer globais.
Então, usei variáveis de classe e o
@classmethod
decorador para conseguir isso.Com minha classe simples de Log, eu poderia fazer o seguinte:
Então, no meu código, se eu quisesse cuspir um monte de informações de depuração, simplesmente precisava codificar
Erros podem ser colocados com
No ambiente de "produção", posso especificar
e agora, apenas a mensagem de erro será exibida. A mensagem de depuração não será impressa.
Aqui está a minha turma:
E algum código que o testa um pouco:
fonte
Construtores alternativos são o exemplo clássico.
fonte
Quando um usuário faz login no meu site, um objeto User () é instanciado a partir do nome de usuário e senha.
Se eu precisar de um objeto de usuário sem que o usuário esteja lá para efetuar login (por exemplo, um usuário administrador pode excluir outra conta de usuário, é necessário instanciar esse usuário e chamar seu método de exclusão):
Eu tenho métodos de classe para pegar o objeto de usuário.
fonte
Eu acho que a resposta mais clara é a de AmanKow . Tudo se resume a como você deseja organizar seu código. Você pode escrever tudo como funções no nível do módulo, que estão agrupadas no espaço para nome do módulo, ou seja,
O código de procedimento acima não está bem organizado, como você pode ver após apenas três módulos, fica confuso, o que cada método faz? Você pode usar nomes descritivos longos para funções (como em java), mas ainda assim seu código fica incontrolável muito rapidamente.
A maneira orientada a objetos é dividir seu código em blocos gerenciáveis, ou seja, classes e objetos e funções podem ser associados a instâncias de objetos ou a classes.
Com as funções de classe, você obtém outro nível de divisão no seu código em comparação com as funções no nível do módulo. Assim, você pode agrupar funções relacionadas dentro de uma classe para torná-las mais específicas a uma tarefa que você atribuiu a essa classe. Por exemplo, você pode criar uma classe de utilitário de arquivo:
Dessa forma, é mais flexível e mais sustentável, você agrupa funções e fica mais óbvio o que cada função faz. Além disso, você evita conflitos de nome, por exemplo, a cópia da função pode existir em outro módulo importado (por exemplo, cópia de rede) que você usa no seu código; portanto, quando você usa o nome completo FileUtil.copy (), remove o problema e as duas funções de cópia pode ser usado lado a lado.
fonte
FileUtil
métodos de classe como funções de umfile_util
módulo, seria comparável e não abusaria do OOP quando nenhum objeto realmente existir (na verdade, você poderia argumentar que é preferível, porque você não acaba comfrom file_util import FileUtil
outra verbosidade). Os conflitos de nome também podem ser evitados no código processual, aoimport file_util
invés defrom file_util import ...
.Honestamente? Eu nunca encontrei um uso para staticmethod ou classmethod. Ainda estou para ver uma operação que não pode ser feita usando uma função global ou um método de instância.
Seria diferente se o python usasse membros privados e protegidos mais como o Java. Em Java, preciso de um método estático para acessar os membros privados de uma instância para fazer as coisas. No Python, isso raramente é necessário.
Normalmente, vejo pessoas usando métodos estáticos e métodos de classe quando tudo o que eles realmente precisam fazer é usar os espaços de nome no nível do módulo do python.
fonte
Ele permite escrever métodos de classe genéricos que você pode usar com qualquer classe compatível.
Por exemplo:
Se você não usar,
@classmethod
poderá fazê-lo com a palavra-chave self, mas ela precisará de uma instância da Class:fonte
Eu trabalhava com PHP e recentemente me perguntei: o que está acontecendo com esse método de classe? O manual do Python é muito técnico e possui poucas palavras, portanto não ajudará no entendimento desse recurso. Eu estava pesquisando no Google e encontrei a resposta -> http://code.anjanesh.net/2007/12/python-classmethods.html .
Se você estiver com preguiça de clicar nele. Minha explicação é mais curta e abaixo. :)
em PHP (talvez nem todos vocês conheçam PHP, mas essa linguagem é tão direta que todos devem entender do que estou falando), temos variáveis estáticas como esta:
A saída será nos dois casos 20.
No entanto, em python, podemos adicionar o decorador @classmethod e, portanto, é possível obter as saídas 10 e 20, respectivamente. Exemplo:
Inteligente, não é?
fonte
B.setInnerVar(20)
foi deixado de fora, ele seria impresso10
duas vezes (em vez de gerar um erro na segunda chamada echoInnerBar () que nãoinner_var
foi definida. #Os métodos de classe fornecem um "açúcar semântico" (não sei se esse termo é amplamente usado) - ou "conveniência semântica".
Exemplo: você tem um conjunto de classes representando objetos. Você pode querer ter o método de classe
all()
oufind()
escreverUser.all()
ouUser.find(firstname='Guido')
. Isso pode ser feito usando funções no nível do módulo, é claro ...fonte
O que me ocorreu, vindo de Ruby, é que o chamado método de classe e o chamado método de instância são apenas uma função com significado semântico aplicado ao seu primeiro parâmetro, que é passado silenciosamente quando a função é chamada como método de um objeto (ie
obj.meth()
).Normalmente esse objeto deve ser uma instância, mas o
@classmethod
decorador do método altera as regras para passar uma classe. Você pode chamar um método de classe em uma instância (é apenas uma função) - o primeiro argumento será sua classe.Por ser apenas uma função , ela só pode ser declarada uma vez em um determinado escopo (ou seja,
class
definição). Se segue, portanto, como uma surpresa para um Rubyist, você não pode ter um método de classe e um método de instância com o mesmo nome .Considere isto:
Você pode chamar
foo
uma instânciaMas não em uma aula:
Agora adicione
@classmethod
:Chamar uma instância agora passa sua classe:
assim como chamar uma classe:
É apenas a convenção que determina que usamos
self
para esse primeiro argumento em um método de instância ecls
em um método de classe. Não usei nenhum aqui para ilustrar que é apenas uma discussão. Em Ruby,self
é uma palavra - chave.Contraste com Ruby:
O método da classe Python é apenas uma função decorada e você pode usar as mesmas técnicas para criar seus próprios decoradores . Um método decorado envolve o método real (no caso
@classmethod
dele passa o argumento de classe adicional). O método subjacente ainda está lá, oculto, mas ainda acessível .nota de rodapé: escrevi isso depois que um conflito de nome entre uma classe e um método de instância despertou minha curiosidade. Estou longe de ser um especialista em Python e gostaria de comentar se algo está errado.
fonte
super()
). AFICT, a "mágica" acontece quando um atributo é definido ou lido. A chamadaobj.meth(arg)
em Python (ao contrário de Ruby) significa simplesmente(obj.meth)(arg)
. Nada é passado silenciosamente para qualquer lugar;obj.meth
é apenas um objeto que pode ser chamado que aceita um argumento a menos que a função da qual foi criado.obj.meth
, por sua vez, significa simplesmentegetattr(obj, "meth")
.Este é um tópico interessante. Minha opinião é que o método de classe python opera como um singleton em vez de uma fábrica (que retorna uma instância de uma classe produzida). A razão de ser um singleton é que existe um objeto comum que é produzido (o dicionário), mas apenas uma vez para a classe, mas compartilhado por todas as instâncias.
Para ilustrar isso aqui é um exemplo. Observe que todas as instâncias têm uma referência ao dicionário único. Este não é o padrão de fábrica como eu o entendo. Provavelmente isso é muito exclusivo do python.
fonte
Eu estava me fazendo a mesma pergunta algumas vezes. E mesmo que os caras aqui tenham se esforçado para explicar, IMHO, a melhor resposta (e a mais simples) que eu encontrei é a descrição do método Class na documentação do Python.
Há também referência ao método estático. E caso alguém já conheça métodos de instância (que eu assumo), essa resposta pode ser a peça final para juntar tudo ...
Uma elaboração mais aprofundada e detalhada sobre este tópico também pode ser encontrada na documentação: A hierarquia de tipos padrão (role para baixo até a seção Métodos de instância )
fonte
@classmethod
pode ser útil para instanciar facilmente objetos dessa classe a partir de recursos externos. Considere o seguinte:Em outro arquivo:
O acesso ao inst.x fornecerá o mesmo valor que as configurações ['x'].
fonte
Uma classe define um conjunto de instâncias, é claro. E os métodos de uma classe trabalham nas instâncias individuais. Os métodos de classe (e variáveis) são um local para pendurar outras informações relacionadas ao conjunto de instâncias.
Por exemplo, se sua turma define um conjunto de alunos, você pode querer variáveis ou métodos de classe que definam coisas como o conjunto de notas em que os alunos podem ser membros.
Você também pode usar métodos de classe para definir ferramentas para trabalhar em todo o conjunto. Por exemplo, Student.all_of_em () pode retornar todos os alunos conhecidos. Obviamente, se seu conjunto de instâncias tiver mais estrutura do que apenas um conjunto, você poderá fornecer métodos de classe para conhecer essa estrutura. Students.all_of_em (grade = 'juniors')
Técnicas como essa tendem a levar ao armazenamento de membros do conjunto de instâncias em estruturas de dados enraizadas nas variáveis de classe. Você precisa tomar cuidado para evitar frustrar a coleta de lixo.
fonte