Question

J'apprends Python et ma dernière leçon à tirer est que Python n'est pas Java, et donc, je viens de passé tout en se tournant tous mes méthodes de la Classe en fonctions.

Je me rends compte maintenant que je n'ai pas besoin d'utiliser les méthodes de la Classe pour ce que je fait avec static méthodes en Java, mais maintenant, je ne suis pas sûr quand je les utiliserais.Tous les conseils que je peux trouver sur Python les méthodes de la Classe est le long de la lignes de débutants comme moi devraient orienter clairement d'entre eux, et le standard de la documentation est à son plus opaque lorsqu'ils discutent entre eux.

Quelqu'un aurait-il un bon exemple d'utilisation d'une méthode de Classe en Python ou au moins quelqu'un peut me dire quand les méthodes de la Classe peut être avantageusement utilisé?

Était-ce utile?

La solution

Les méthodes de la classe sont pour quand vous avez besoin d'avoir des méthodes qui ne sont pas spécifiques à une instance particulière, mais encore par la classe d'une certaine façon.La chose la plus intéressante à leur sujet est qu'ils peuvent être remplacées par des sous-classes, quelque chose qui n'est tout simplement pas possible en Java de méthodes statiques ou Python module-fonctions de niveau.

Si vous avez une classe MyClass, et au niveau du module de la fonction qui fonctionne sur MyClass (usine d'injection de dépendance stub, etc), d'en faire un classmethod.Ensuite, il sera disponible pour les sous-classes.

Autres conseils

Usine de méthodes alternatives (constructeurs) sont en effet un exemple classique de méthodes de la classe.

Fondamentalement, les méthodes de classe sont adaptés à tout moment vous souhaitez avoir une méthode qui s'inscrit naturellement dans l'espace de noms de la classe, mais n'est pas associée à une instance particulière de la classe.

Par exemple, dans l'excellent unipath module:

Répertoire courant

  • Path.cwd()
    • Retour au réel répertoire courant;par exemple, Path("/tmp/my_temp_dir").C'est une méthode de classe.
  • .chdir()
    • Faire soi-même est le répertoire courant.

Le répertoire courant est un processus de large, l' cwd la méthode n'a pas d'exemple particulier avec qui il doit être associé.Toutefois, la modification de la cwd dans le répertoire d'un Path exemple devrait en effet être une méthode d'instance.

Hmmm...comme Path.cwd() en effet, de retour d'un Path exemple, je suppose que cela pourrait être considéré comme une méthode de fabrique...

Pensez-y de cette façon:normal méthodes sont utiles pour masquer les détails de l'expédition:vous pouvez taper myobj.foo() sans se soucier de savoir si l' foo() la méthode est mise en œuvre par le myobj classe de l'objet ou de l'une de ses classes parentes.Les méthodes de la classe sont exactement analogue, mais avec la classe de l'objet à la place:ils vous permettent d'appeler MyClass.foo() sans avoir à se soucier de savoir si foo() est mis en œuvre spécialement par MyClass car elle a besoin de son propre version spécialisée, ou si c'est de laisser sa classe parente traiter l'appel.

Les méthodes de la classe sont essentielles lorsque vous faites du set-up ou de calcul qui précède la création d'une instance réelle, parce que jusqu'à ce que l'instance existe de toute évidence vous ne pouvez pas utiliser l'instance que l'envoi, pour vos appels de méthode.Un bon exemple peut être vu dans la SQLAlchemy code source;jetez un oeil à la dbapi() méthode de la classe sur le lien suivant:

https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47

Vous pouvez voir que le dbapi() méthode, qui est une base de données backend utilise pour importer spécifique au fournisseur de base de données de la bibliothèque dont il a besoin à la demande, est une méthode de classe, car il a besoin pour fonctionner avant cas particulier d'une connexion de base de données commencez à recevoir créé — mais qu'il ne peut pas être une simple fonction ou une fonction statique, parce qu'ils veulent être en mesure d'appeler les autres, en soutenant les méthodes susceptibles de même besoin d'être écrit plus précisément dans les sous-classes que dans leur classe parent.Et si vous envoi à une fonction ou d'une classe statique, vous "oubliez" et de perdre la connaissance de la classe est en train de faire l'initialisation.

J'ai récemment voulu un très léger-poids classe de log qui serait sortie des quantités variables de sortie en fonction du niveau d'enregistrement peut être réglée par programme.Mais je ne voulais pas d'instancier la classe à chaque fois que je voulais à la sortie d'un message de débogage ou d'erreur ou d'avertissement.Mais je voulais aussi encapsuler le fonctionnement de cette fonction de journalisation et de le rendre réutilisable sans la déclaration de toutes les variables globales.

Alors j'ai utilisé des variables de classe et l' @classmethod décorateur pour atteindre cet objectif.

Avec ma classe de log, j'ai pu effectuer les opérations suivantes:

Logger._level = Logger.DEBUG

Alors, dans mon code, si je voulais cracher un tas d'informations de débogage, j'ai simplement eu à code

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

Les erreurs pourraient être mis avec

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

Dans la "production" de l'environnement, je peux préciser

Logger._level = Logger.ERROR

et maintenant, seul le message d'erreur sera de sortie.Le message de débogage ne sera pas imprimé.

Voici ma 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

Et un peu de code qui teste juste un peu:

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()

Alternative constructeurs sont un exemple classique.

Je pense que le plus clair de réponse est AmanKow de l' un.Il se résume à comment tu veux organiser votre code.Vous pouvez écrire tout ce que le module de fonctions de niveau qui sont enveloppés dans l'espace de nommage du module.e

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()

La procédure décrite ci-dessus le code n'est pas bien organisé, comme vous pouvez le voir, après seulement 3 modules, il devient source de confusion, qu'est-ce que chaque méthode ?Vous pouvez utilisez des noms descriptifs pour les fonctions(comme en java), mais encore votre code devient ingérable très rapide.

L'orienté objet moyen est de briser votre code en plusieurs blocs j'.e Classes et les objets et les fonctions peuvent être associés à des objets ou instances des classes.

Avec des fonctions de classe vous gagnez un autre niveau de la division dans votre code en comparaison avec le module de fonctions de niveau.Ainsi, vous pouvez regrouper les fonctions au sein d'une classe pour les rendre plus spécifiques à une tâche que vous avez attribué à cette classe.Par exemple, vous pouvez créer un fichier de l'utilitaire de la classe :

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")

De cette manière, plus souple et plus facile à gérer, vous groupe de fonctions ensemble, et ses plus évident à ce que chaque fonction.Aussi vous éviter les conflits de nom, par exemple, la fonction copie peut exister dans un autre module importé(par exemple, les réseaux de copie) que vous utilisez dans votre code, de sorte que lorsque vous utilisez le nom complet FileUtil.copier() vous retirez le problème et les deux fonctions de copie peuvent être utilisés en parallèle.

Lorsqu'un utilisateur se connecte sur mon site, un Utilisateur() de l'objet est instancié à partir du nom d'utilisateur et mot de passe.

Si j'ai besoin d'un objet utilisateur, sans que l'utilisateur il y a une session (par ex.un admin utilisateur peut supprimer l'autre compte utilisateurs, donc j'ai besoin d'instancier l'utilisateur et appeler sa méthode de suppression):

J'ai méthodes de la classe pour saisir l'objet utilisateur.

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()

Honnêtement?Je n'ai jamais trouvé une utilisation pour staticmethod ou classmethod.Je n'ai pas encore vu une opération qui ne peut pas être fait à l'aide d'une fonction globale ou une méthode d'instance.

Ce serait différent si python utilisé membres privés et protégés plus comme Java.En Java, j'ai besoin d'une méthode statique pour être en mesure d'accéder à une instance privée de membres à faire des trucs.En Python, c'est rarement nécessaire.

Habituellement, je vois des gens à l'aide de staticmethods et classmethods quand tout ce qu'ils ont vraiment besoin de faire est d'utiliser python au niveau du module d'espaces de noms de mieux.

Il vous permet d'écrire la classe générique des méthodes que vous pouvez utiliser avec n'importe quel classe.

Par exemple:

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

class C:
    name = "tester"

C.get_name = get_name

#call it:
C.get_name()

Si vous n'utilisez pas @classmethod vous pouvez le faire avec mot-clé self, mais il a besoin d'une instance 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

J'ai l'habitude de travailler avec PHP et récemment, j'ai été me demandant ce qui se passe avec cette classmethod?Python manuel est très technique et très court de mots, alors il l'habitude d'aider à la compréhension de la fonctionnalité.J'ai été googler et une recherche sur google et j'ai trouvé la réponse -> http://code.anjanesh.net/2007/12/python-classmethods.html.

Si vous avez la flemme de cliquer dessus.Mon explication est plus court et ci-dessous.:)

en PHP (peut-être pas vous le savez tous PHP, mais cette langue est aussi simple que tout le monde devrait comprendre de quoi je parle), nous avons les variables statiques comme ceci:


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();

La sortie sera dans les deux cas, 20.

Cependant en python on peut ajouter @classmethod décorateur et donc il est possible d'avoir à la sortie 10 et 20 respectivement.Exemple:


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()

Intelligent, n'est-ce pas?

Les méthodes de la classe de fournir une sémantique "sucre" (je ne sais pas si ce terme est largement utilisé) ou sémantique "de commodité".

Exemple:vous avez un ensemble de classes représentant des objets.Vous pourriez avoir à la méthode de classe all() ou find() pour écrire User.all() ou User.find(firstname='Guido').Qui pourrait être fait à l'aide du module de fonctions de niveau de cours...

Ce qui vient de me frapper, venant de Rubis, est qu'un soi-disant classe méthode et un soi-disant exemple la méthode est juste une fonction sémantique appliquée à son premier paramètre, qui est discrètement passé quand la la fonction s'appelle une méthode d'un objet (c'est à dire obj.meth()).

Normalement c' objet doit être une instance, mais l' @classmethod méthode décorateur change les règles pour passer d'une classe.Vous pouvez appeler une méthode d'une classe sur une instance (c'est juste une fonction) - le premier argyment sera sa classe.

Parce que c'est juste un la fonction, il ne peut être déclarée une fois sur une étendue donnée (c'est à dire class la définition).Il s'ensuit, par conséquent, une surprise pour un Rubyist, que vous ne pouvez pas avoir une méthode de classe et une méthode d'instance avec le même nom.

Réfléchissez à ceci:

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

Vous pouvez appeler foo sur une instance

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

Mais pas sur une 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)

Ajouter maintenant @classmethod:

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

Le recours à une instance transmet désormais sa classe:

Foo().foo()
__main__.Foo

comme le fait l'appel sur une classe:

Foo.foo()
__main__.Foo

C'est seulement de la convention qui stipule que nous utilisons self pour ce premier argument d'une méthode d'instance et cls sur une méthode de classe.J'ai utilisé ni ici, pour illustrer que c'est juste un argument.En Ruby, self est un mot-clé.

Le contraste avec 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>

Le Python de la méthode de classe est juste un décoré de la fonction et vous pouvez utiliser les mêmes techniques pour créez votre propre décorateurs.Décoré de la méthode se terminera le réel de la méthode (dans le cas de @classmethod il passe à la classe supplémentaire argument).Le sous-jacentes de la méthode est toujours là, caché mais toujours accessible.


note de bas de page:Je l'ai écrit après un conflit de nom entre une classe et une méthode d'instance a piqué ma curiosité.Je suis loin d'être un expert Python et voudrais des commentaires si tout cela est faux.

C'est un sujet intéressant.Mon prendre sur elle, c'est que python classmethod fonctionne comme un singleton plutôt que d'une usine (qui renvoie un produit d'une instance d'une classe).La raison pour laquelle il est un singleton est qu'il y a un objet qui est produit (dans le dictionnaire), mais une seule fois pour la catégorie, mais partagée par toutes les instances.

Pour illustrer cela, voici un exemple.Notez que toutes les instances ont une référence à l'unique dictionnaire.Ce n'est pas l'Usine modèle de ce que je comprends.C'est probablement très unique pour 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

Je me posais la même question à quelques reprises.Et même si les gars ici ont essayé difficile de l'expliquer, à mon humble avis la meilleure réponse (et plus simple) réponse que j'ai trouvé, c'est l' description de la méthode de Classe dans la Documentation Python.

Il ya aussi référence à la méthode Statique.Et dans le cas où quelqu'un l'a déjà connaître les méthodes d'instance (qui, je suppose), cette réponse pourrait être la dernière pièce de mettre tout cela ensemble...

Plus loin et plus profond élaboration sur ce sujet peut aussi être trouvée dans la documentation:La norme de la hiérarchie des types de (faites défiler vers le bas pour Les méthodes d'Instance la section)

Une classe définit un ensemble d'instances, bien sûr.Et les méthodes de travail en classe sur les cas individuels.Les méthodes de la classe (et variables) d'un endroit pour accrocher d'autres informations relatives à l'ensemble des instances-dessus de tous.

Par exemple, si votre classe définit un ensemble de étudiants que vous pourriez classe des variables ou des méthodes qui définissent des choses comme l'ensemble de grade, les élèves peuvent être membres de.

Vous pouvez également utiliser les méthodes de la classe pour définir les outils permettant de travailler sur l'ensemble de la série.Pour l'exemple de l'Étudiant.all_of_em() peut retourner toutes connues des étudiants.Évidemment, si votre ensemble d'instances ont plus de structure que juste un jeu, vous pouvez fournir des méthodes de la classe de connaître cette structure.Les étudiants.all_of_em(grade='juniors')

Des Techniques comme cette tendance à conduire à stocker des membres de l'ensemble des instances dans des structures de données qui sont enracinées dans des variables de classe.Vous devez prendre soin de ne pas frustrer la collecte des ordures alors.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top