Quais são os métodos de classe em Python para?

votos
216

Eu estou ensinando-me Python e minha lição mais recente foi o Python não é Java , e por isso eu só passei um tempo transformando todos os meus métodos de classe em funções.

Agora percebo que eu não preciso usar métodos de classe para o que eu iria fazer com staticmétodos em Java, mas agora eu não tenho certeza de quando eu iria usá-los. Todo o conselho que eu posso encontrar sobre métodos Python classe é ao longo das linhas de novatos como eu deve ficar longe deles, e a documentação padrão é, na sua mais opaca quando discuti-las.

Alguém tem um bom exemplo do uso de um método de classe em Python ou, pelo menos, alguém pode me dizer quando os métodos de classe pode ser usada de forma sensata?

Publicado 01/09/2008 em 19:16
fonte usuário
Em outras línguas...                            


15 respostas

votos
158

Métodos de classe são para quando você precisa ter métodos que não são específicos para qualquer caso particular, mas ainda envolvem a classe de alguma forma. A coisa mais interessante sobre eles é que eles podem ser substituídas por subclasses, algo que simplesmente não é possível em métodos estáticos de Java ou funções de nível módulo do Python.

Se você tem uma classe MyClass, e uma função de nível de módulo que opera em MyClass (fábrica, dependência esboço injeção, etc), torná-lo um classmethod. Em seguida, ele vai estar disponível para subclasses.

Respondeu 01/09/2008 em 19:45
fonte usuário

votos
60

métodos de fábrica (construtores alternativos) são, de facto um exemplo clássico de métodos de classe.

Basicamente, métodos de classe são adequados a qualquer momento você gostaria de ter um método que se encaixa naturalmente no espaço de nomes da classe, mas não está associada a uma instância específica da classe.

Como um exemplo, na excelente Unipath módulo:

Diretório atual

  • Path.cwd()
    • Retornar o diretório atual; por exemplo, Path("/tmp/my_temp_dir"). Este é um método de classe.
  • .chdir()
    • Faça auto diretório atual.

À medida que o directório actual é o processo de largura, o cwdmétodo não tem nenhum exemplo particular com a qual deve ser associada. No entanto, alterar o cwdpara o diretório de uma determinada Pathinstância deve realmente ser um método de instância.

Hmmm ... como Path.cwd()de fato retornar um Pathexemplo, eu acho que poderia ser considerado como um método de fábrica ...

Respondeu 01/09/2008 em 20:08
fonte usuário

votos
44

Pense nisso desta maneira: métodos normais são úteis para esconder os detalhes de envio: você pode digitar myobj.foo()sem se preocupar se o foo()método é implementado pela myobjclasse de objeto ou uma de suas classes pai. Métodos de classe são exatamente análoga a esta, mas com o objeto de classe em vez disso: eles permitem que você chamar MyClass.foo()sem ter que se preocupar se foo()é implementado especialmente por MyClassporque precisava de sua própria versão especializada, ou se ele está deixando sua classe pai lidar com a chamada.

Métodos de classe são essenciais quando você está fazendo set-up ou estimativa, que precede a criação de uma instância real, porque até que a instância existe obviamente você não pode usar a instância como o ponto de expedição para as suas chamadas de método. Um bom exemplo pode ser visto 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 backend de banco de dados usa para importar a biblioteca de banco de dados específica do fornecedor que necessita on-demand, é um método de classe, porque ele precisa ser executado antes de instâncias de uma conexão de banco de dados específico começam a ser criadas -, mas que não pode ser uma função simples ou função estática, porque eles querem que ele seja capaz de chamar outros métodos, apoio que pode semelhante precisam ser escritas mais especificamente em subclasses que na sua classe pai. E se você despachar a uma função ou classe estática, então você "esquecer" e perder o conhecimento sobre qual classe está fazendo o Inicializar.

Respondeu 19/08/2010 em 13:51
fonte usuário

votos
26

Recentemente queria uma classe de log muito leve que a saída quantidades variáveis ​​de saída, dependendo do nível de registo que pode ser programaticamente definido. Mas eu não queria instanciar a classe cada vez que eu queria produzir uma mensagem de depuração ou erro ou aviso. Mas eu também queria para encapsular o funcionamento desta facilidade de registro e torná-lo reutilizável sem a declaração de qualquer globals.

Então eu usei variáveis de classe e do @classmethoddecorador para conseguir isso.

Com a minha turma de registo simples, eu poderia fazer o seguinte:

Logger._level = Logger.DEBUG

Então, no meu código, se eu quisesse cuspir um monte de informações de depuração, eu simplesmente tinha que codificar

Logger.debug( "this is some annoying message I only want to see while debugging" )

Erros poderia ser posto para fora com

Logger.error( "Wow, something really awful happened." )

No ambiente de "produção", posso especificar

Logger._level = Logger.ERROR

e agora, somente a mensagem de erro será emitido. A mensagem de depuração não será impressa.

Aqui está minha classe:

class Logger :
    ''' Handles logging of debugging and error messages. '''

    DEBUG = 5
    INFO  = 4
    WARN  = 3
    ERROR = 2
    FATAL = 1
    _level = DEBUG

    def __init__( self ) :
        Logger._level = Logger.DEBUG

    @classmethod
    def isLevel( cls, level ) :
        return cls._level >= level

    @classmethod
    def debug( cls, message ) :
        if cls.isLevel( Logger.DEBUG ) :
            print "DEBUG:  " + message

    @classmethod
    def info( cls, message ) :
        if cls.isLevel( Logger.INFO ) :
            print "INFO :  " + message

    @classmethod
    def warn( cls, message ) :
        if cls.isLevel( Logger.WARN ) :
            print "WARN :  " + message

    @classmethod
    def error( cls, message ) :
        if cls.isLevel( Logger.ERROR ) :
            print "ERROR:  " + message

    @classmethod
    def fatal( cls, message ) :
        if cls.isLevel( Logger.FATAL ) :
            print "FATAL:  " + message

E algum código que testa-lo um pouco:

def logAll() :
    Logger.debug( "This is a Debug message." )
    Logger.info ( "This is a Info  message." )
    Logger.warn ( "This is a Warn  message." )
    Logger.error( "This is a Error message." )
    Logger.fatal( "This is a Fatal message." )

if __name__ == '__main__' :

    print "Should see all DEBUG and higher"
    Logger._level = Logger.DEBUG
    logAll()

    print "Should see all ERROR and higher"
    Logger._level = Logger.ERROR
    logAll()
Respondeu 11/05/2010 em 02:48
fonte usuário

votos
23

construtores alternativas são o exemplo clássico.

Respondeu 01/09/2008 em 19:27
fonte usuário

votos
10

Eu acho que a resposta mais clara é de AmanKow um. Tudo se resume à forma como u quer organizar seu código. Você pode escrever tudo como funções de nível módulo que são envolvidos no namespace do módulo ie

module.py (file 1)
---------
def f1() : pass
def f2() : pass
def f3() : pass


usage.py (file 2)
--------
from module import *
f1()
f2()
f3()
def f4():pass 
def f5():pass

usage1.py (file 3)
-------------------
from usage import f4,f5
f4()
f5()

O código de procedimento acima não é bem organizado, como você pode ver depois de apenas 3 módulos que ele fica confuso, o que é cada método de fazer? Você pode usar nomes descritivos longos para funções (como em java), mas ainda seu código fica incontrolável muito rápido.

A maneira orientada a objeto é quebrar o código em blocos gerenciáveis, ou seja, Aulas e objetos e funções podem ser associados a instâncias de objetos ou com classes.

Com funções de classe você ganha outro nível de divisão em seu código em comparação com funções de nível de módulo. Assim você pode funções de grupo relacionadas dentro de uma classe para torná-los mais específico para uma tarefa que você atribuiu a essa classe. Por exemplo, você pode criar uma classe de utilitário de arquivo:

class FileUtil ():
  def copy(source,dest):pass
  def move(source,dest):pass
  def copyDir(source,dest):pass
  def moveDir(source,dest):pass

//usage
FileUtil.copy("1.txt","2.txt")
FileUtil.moveDir("dir1","dir2")

Desta forma, é mais flexível e mais sustentável, agrupar funções juntos e é mais óbvio para o que cada função faz. Também você evitar conflitos de nomes, por exemplo, a cópia da função deve existir em outro módulo importado (para copiar exemplo de rede) que você usa no seu código, então quando você usar o nome completo FileUtil.copy () de remover o problema e ambas as funções de cópia podem ser usados ​​lado a lado.

Respondeu 14/05/2011 em 11:24
fonte usuário

votos
8

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 estar lá para entrar (por exemplo, um usuário administrador pode querer excluir outra conta usuários, assim que eu preciso para criar uma instância que o usuário e chamar seu método delete):

Eu tenho métodos de classe para agarrar o objeto de usuário.

class User():
    #lots of code
    #...
    # more code

    @classmethod
    def get_by_username(cls, username):
        return cls.query(cls.username == username).get()

    @classmethod
    def get_by_auth_id(cls, auth_id):
        return cls.query(cls.auth_id == auth_id).get()
Respondeu 26/03/2012 em 07:36
fonte usuário

votos
6

Ele permite que você escrever métodos de classe genéricos que você pode usar com qualquer classe compatível.

Por exemplo:

@classmethod
def get_name(cls):
    print cls.name

class C:
    name = "tester"

C.get_name = get_name

#call it:
C.get_name()

Se você não usa @classmethod, você pode fazê-lo com auto palavra-chave, mas ele precisa de uma instância de Classe:

def get_name(self):
    print self.name

class C:
    name = "tester"

C.get_name = get_name

#call it:
C().get_name() #<-note the its an instance of class C
Respondeu 26/12/2012 em 16:11
fonte usuário

votos
6

Eu costumava trabalhar com PHP e, recentemente, eu estava me perguntando, o que está acontecendo com este classmethod? Manual do Python é muito técnico e muito curto em palavras, por isso não vai ajudar a compreender esse recurso. Eu estava pesquisando e pesquisando e encontrei resposta -> http://code.anjanesh.net/2007/12/python-classmethods.html .

Se você é preguiçoso para clicar nele. Minha explicação é mais curto e abaixo. :)

em PHP (talvez não todos vocês sabem PHP, mas essa linguagem é tão simples que todos devem entender o que estou falando) nós temos variáveis ​​estáticas como este:


class A
{

    static protected $inner_var = null;

    static public function echoInnerVar()
    {
        echo self::$inner_var."\n";
    }

    static public function setInnerVar($v)
    {
        self::$inner_var = $v;
    }

}

class B extends A
{
}

A::setInnerVar(10);
B::setInnerVar(20);

A::echoInnerVar();
B::echoInnerVar();

A saída será em ambos os casos 20.

No entanto, em python, podemos acrescentar decorador @classmethod e, portanto, é possível ter saída 10 e 20, respectivamente. Exemplo:


class A(object):
    inner_var = 0

    @classmethod
    def setInnerVar(cls, value):
        cls.inner_var = value

    @classmethod
    def echoInnerVar(cls):
        print cls.inner_var


class B(A):
    pass


A.setInnerVar(10)
B.setInnerVar(20)

A.echoInnerVar()
B.echoInnerVar()

Inteligente, não é?

Respondeu 22/02/2010 em 14:27
fonte usuário

votos
4

Métodos de classe fornecer um "açúcar semântica" (não sei se este termo é amplamente utilizado) - ou "conveniência semântica".

Exemplo: você tem um conjunto de classes que representam objetos. Você pode querer ter o método de classe all()ou find()para escrever User.all()ou User.find(firstname='Guido'). Isso poderia ser feito usando funções de nível de módulo, é claro ...

Respondeu 17/08/2010 em 16:53
fonte usuário

votos
4

Honestamente? Eu nunca encontrei um uso para staticmethod ou classmethod. Eu ainda tenho que ver uma operação que não pode ser feito usando uma função global ou um método de instância.

Seria diferente se python utilizado privada e protegida membros mais como Java faz. Em Java, eu preciso de um método estático para ser capaz de acessar os membros privados de uma instância para fazer coisas. Em Python, que é raramente necessário.

Normalmente, eu vejo as pessoas usando staticmethods e classmethods quando tudo o que realmente precisa fazer é em nível de módulo de uso de python namespaces melhor.

Respondeu 01/09/2008 em 19:54
fonte usuário

votos
2

O que acabou de me bater, vindo de Ruby, é que a chamada classe método e um chamado instância método é apenas uma função com significado semântico aplicada ao seu primeiro parâmetro, que é passado em silêncio quando a função é chamada como um método de um objecto (ou seja obj.meth()).

Normalmente isso objeto deve ser uma instância, mas o @classmethod método decorador muda as regras para passar uma classe. Você pode chamar um método de classe em uma instância (que é apenas uma função) - o primeiro argyment será sua classe.

Porque é apenas uma função , ela só pode ser declarada uma vez em um determinado escopo (ie classdefinição). Se segue, portanto, como uma surpresa para a Rubyist, que você não pode ter um método de classe e um método de instância com o mesmo nome .

Considere isto:

class Foo():
  def foo(x):
    print(x)

Você pode chamar fooem uma instância

Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>

Mas não em uma classe:

Foo.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)

Agora adicione @classmethod:

class Foo():
  @classmethod
  def foo(x):
    print(x)

Chamando em uma instância passa agora sua classe:

Foo().foo()
__main__.Foo

como se chama em uma classe:

Foo.foo()
__main__.Foo

É única convenção que determina que usamos selfpara esse primeiro argumento em um método de instância e clsem um método de classe. Eu usei nem aqui para ilustrar que é apenas um argumento. Em Ruby, selfé uma palavra-chave.

Contraste com Ruby:

class Foo
  def foo()
    puts "instance method #{self}"
  end
  def self.foo()
    puts "class method #{self}"
  end
end

Foo.foo()
class method Foo

Foo.new.foo()
instance method #<Foo:0x000000020fe018>

O método de classe Python é apenas uma função decorados 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 de @classmethodele passa o argumento de classe adicional). O método subjacente ainda está lá, escondido , mas ainda acessíveis .


nota: eu escrevi isto depois de um confronto nome entre um método de classe e instância despertou minha curiosidade. Estou longe de ser um especialista em Python e gostaria de comentários se nada disto é errado.

Respondeu 24/03/2017 em 20:45
fonte usuário

votos
2

Este é um tópico interessante. Minha opinião sobre isso é que python classmethod funciona como um singleton em vez de uma fábrica (que retorna um produziu uma instância de uma classe). A razão é um singleton é que há um objeto comum que é produzido (o dicionário), mas apenas uma vez para a classe, mas compartilhado por todas as instâncias.

Para ilustrar este aqui é um exemplo. Note-se que todas as instâncias têm uma referência para o único dicionário. Este não é o padrão de fábrica como eu o entendo. Este é provavelmente muito original para python.

class M():
 @classmethod
 def m(cls, arg):
     print "arg was",  getattr(cls, "arg" , None),
     cls.arg = arg
     print "arg is" , cls.arg

 M.m(1)   # prints arg was None arg is 1
 M.m(2)   # prints arg was 1 arg is 2
 m1 = M()
 m2 = M() 
 m1.m(3)  # prints arg was 2 arg is 3  
 m2.m(4)  # prints arg was 3 arg is 4 << this breaks the factory pattern theory.
 M.m(5)   # prints arg was 4 arg is 5
Respondeu 07/09/2012 em 06:06
fonte usuário

votos
1

Eu estava me perguntando a mesma pergunta várias vezes. E mesmo que os caras aqui se esforçou para explicar isso, IMHO a melhor resposta (e mais simples) resposta que eu tenho encontrado é a descrição do método de classe na Documentação do Python.

Há também referência ao método estático. E no caso de alguém já conhece os métodos de instância (que eu suponho), esta resposta pode ser a peça final para colocá-lo todos juntos ...

Mais e elaboração mais profunda sobre este tema pode ser encontrada também na documentação: A hierarquia de tipo padrão (desloque-se para métodos Instância seção)

Respondeu 14/10/2014 em 08:07
fonte usuário

votos
0

A classe define um conjunto de instâncias, é claro. E os métodos de um trabalho de classe sobre os casos individuais. Os métodos de classe (e variáveis) um lugar para pendurar outra informação que está relacionada com o conjunto de instâncias sobre tudo.

Por exemplo, se sua classe define um conjunto de estudantes que você pode querer variáveis ​​ou métodos que definem coisas como o conjunto de grau os alunos podem ser membros de classe.

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 o seu conjunto de instâncias têm mais estrutura do que apenas um conjunto que pode fornecer métodos de classe para saber sobre essa estrutura. Students.all_of_em (grau = '') juniors

Técnicas como esta tendem a levar a armazenar os membros do conjunto de instâncias em estruturas de dados que estão enraizadas em variáveis ​​de classe. Você precisa tomar cuidado para evitar frustrar a coleta de lixo em seguida.

Respondeu 08/09/2016 em 01:29
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more