J'apprends moi-même Python et ma dernière leçon a été que Python n'est pas Java , et je viens donc de passer un peu de temps à transformer toutes mes méthodes de classe en fonctions.
Je me rends compte maintenant que je n'ai pas besoin d'utiliser des méthodes de classe pour ce que je ferais avec des static
méthodes en Java, mais maintenant je ne sais pas quand je les utiliserais. Tous les conseils que je peux trouver sur les méthodes de classe Python vont dans le sens des débutants comme moi devraient les éviter, et la documentation standard est la plus opaque lors de leur discussion.
Quelqu'un at-il un bon exemple d'utilisation d'une méthode de classe en Python ou au moins quelqu'un peut-il me dire quand les méthodes de classe peuvent être utilisées de manière raisonnable?
la source
obj.cls_mthd(...)
outype(obj).cls_mthd(...)
?Les méthodes d'usine (constructeurs alternatifs) sont en effet un exemple classique de méthodes de classe.
Fondamentalement, les méthodes de classe conviennent à chaque fois que vous souhaitez avoir une méthode qui s'intègre naturellement dans l'espace de noms de la classe, mais qui n'est pas associée à une instance particulière de la classe.
À titre d'exemple, dans l'excellent module unipath :
Répertoire actuel
Path.cwd()
Path("/tmp/my_temp_dir")
. Il s'agit d'une méthode de classe..chdir()
Le répertoire courant étant à l'échelle du processus, la
cwd
méthode n'a pas d'instance particulière à laquelle il doit être associé. Cependant, le changement ducwd
répertoire d'unePath
instance donnée devrait en effet être une méthode d'instance.Hmmm ... comme
Path.cwd()
retourne en effet unePath
instance, je suppose que cela pourrait être considéré comme une méthode d'usine ...la source
Pensez-y de cette façon: les méthodes normales sont utiles pour masquer les détails de la répartition: vous pouvez taper
myobj.foo()
sans vous soucier de savoir si lafoo()
méthode est implémentée par lamyobj
classe de l' objet ou l'une de ses classes parentes. Les méthodes de classe sont exactement analogues à cela, mais avec l'objet classe à la place: elles vous permettent d'appelerMyClass.foo()
sans avoir à vous soucier de savoir sifoo()
est implémenté spécialement parMyClass
car il avait besoin de sa propre version spécialisée, ou s'il laisse sa classe parente gérer l'appel.Les méthodes de classe sont essentielles lorsque vous effectuez une configuration ou un calcul qui précède la création d'une instance réelle, car tant que l'instance n'existe pas, vous ne pouvez évidemment pas utiliser l'instance comme point de répartition pour vos appels de méthode. Un bon exemple peut être consulté dans le code source de SQLAlchemy; jetez un oeil à la
dbapi()
méthode de classe sur le lien suivant:https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47
Vous pouvez voir que la
dbapi()
méthode, qu'un backend de base de données utilise pour importer la bibliothèque de bases de données spécifique au fournisseur dont il a besoin à la demande, est une méthode de classe car elle doit s'exécuter avant que les instances d'une connexion de base de données particulière ne soient créées - mais qu'elle ne peut pas être une fonction simple ou une fonction statique, car ils veulent qu'elle puisse appeler d'autres méthodes de support qui pourraient également devoir être écrites plus spécifiquement dans des sous-classes que dans leur classe parente. Et si vous effectuez une répartition vers une fonction ou une classe statique, vous "oubliez" et perdez la connaissance de la classe qui effectue l'initialisation.la source
J'ai récemment voulu une classe de journalisation très légère qui produirait des quantités variables de sortie en fonction du niveau de journalisation qui pourrait être programmé. Mais je ne voulais pas instancier la classe chaque fois que je voulais afficher un message de débogage ou une erreur ou un avertissement. Mais je voulais aussi encapsuler le fonctionnement de cette fonction de journalisation et la rendre réutilisable sans la déclaration d'aucun global.
J'ai donc utilisé des variables de classe et le
@classmethod
décorateur pour y parvenir.Avec ma classe de journalisation simple, je pouvais faire ce qui suit:
Ensuite, dans mon code, si je voulais cracher un tas d'informations de débogage, je devais simplement coder
Des erreurs pourraient être éliminées avec
Dans l'environnement "production", je peux préciser
et maintenant, seul le message d'erreur sera affiché. Le message de débogage ne sera pas imprimé.
Voici ma classe:
Et du code qui le teste un peu:
la source
Les constructeurs alternatifs en sont l'exemple classique.
la source
Lorsqu'un utilisateur se connecte sur mon site Web, un objet User () est instancié à partir du nom d'utilisateur et du mot de passe.
Si j'ai besoin d'un objet utilisateur sans que l'utilisateur soit là pour se connecter (par exemple, un utilisateur administrateur peut vouloir supprimer un autre compte d'utilisateurs, j'ai donc besoin d'instancier cet utilisateur et d'appeler sa méthode de suppression):
J'ai des méthodes de classe pour saisir l'objet utilisateur.
la source
Je pense que la réponse la plus claire est celle d' AmanKow . Cela se résume à la façon dont vous souhaitez organiser votre code. Vous pouvez tout écrire en tant que fonctions de niveau module qui sont enveloppées dans l'espace de noms du module, c'est-à-dire
Le code procédural ci-dessus n'est pas bien organisé, comme vous pouvez le voir après seulement 3 modules, cela devient confus, que fait chaque méthode? Vous pouvez utiliser des noms descriptifs longs pour les fonctions (comme en java) mais votre code devient néanmoins ingérable très rapidement.
La méthode orientée objet consiste à décomposer votre code en blocs gérables, c'est-à-dire que les classes, les objets et les fonctions peuvent être associés à des instances d'objets ou à des classes.
Avec les fonctions de classe, vous gagnez un autre niveau de division dans votre code par rapport aux fonctions de niveau module. Vous pouvez donc regrouper des fonctions connexes au sein d'une classe pour les rendre plus spécifiques à une tâche que vous avez affectée à cette classe. Par exemple, vous pouvez créer une classe d'utilitaire de fichier:
Cette façon est plus flexible et plus maintenable, vous regroupez les fonctions ensemble et c'est plus évident pour ce que fait chaque fonction. Vous évitez également les conflits de noms, par exemple la copie de fonction peut exister dans un autre module importé (par exemple copie réseau) que vous utilisez dans votre code, donc lorsque vous utilisez le nom complet FileUtil.copy () vous supprimez le problème et les deux fonctions de copie peut être utilisé côte à côte.
la source
FileUtil
méthodes de classe en tant que fonctions d'unfile_util
module, ce serait comparable et n'abuseriez pas de la POO quand aucun objet n'existe réellement (en fait, vous pourriez dire que c'est préférable, car vous ne vous retrouvez pas avecfrom file_util import FileUtil
ou autre verbosité). Les conflits de noms peuvent également être évités dans le code de procédure en faisantimport file_util
au lieu defrom file_util import ...
.Honnêtement? Je n'ai jamais trouvé d'utilisation pour la méthode statique ou la méthode de classe. Je n'ai pas encore vu d'opération qui ne peut pas être effectuée à l'aide d'une fonction globale ou d'une méthode d'instance.
Ce serait différent si python utilisait des membres privés et protégés plus comme Java. En Java, j'ai besoin d'une méthode statique pour pouvoir accéder aux membres privés d'une instance pour faire des choses. En Python, c'est rarement nécessaire.
Habituellement, je vois des gens utiliser des méthodes statiques et des méthodes de classe quand tout ce qu'ils ont vraiment besoin de faire est de mieux utiliser les espaces de noms au niveau du module de python.
la source
Il vous permet d'écrire des méthodes de classe génériques que vous pouvez utiliser avec n'importe quelle classe compatible.
Par exemple:
Si vous ne l'utilisez pas,
@classmethod
vous pouvez le faire avec le mot-clé self mais il a besoin d'une instance de Class:la source
J'avais l'habitude de travailler avec PHP et récemment je me demandais, que se passe-t-il avec cette méthode de classe? Le manuel de Python est très technique et très court en mots, donc il n'aidera pas à comprendre cette fonctionnalité. J'étais sur Google et sur Google et j'ai trouvé la réponse -> http://code.anjanesh.net/2007/12/python-classmethods.html .
Si vous êtes paresseux de cliquer dessus. Mon explication est plus courte et ci-dessous. :)
en PHP (vous ne connaissez peut-être pas tous PHP, mais ce langage est si simple que tout le monde devrait comprendre de quoi je parle), nous avons des variables statiques comme ceci:
La sortie sera dans les deux cas 20.
Cependant en python on peut ajouter @classmethod decorator et ainsi il est possible d'avoir respectivement les sorties 10 et 20. Exemple:
Intelligent, non?
la source
B.setInnerVar(20)
été10
omis , il s'imprimerait deux fois (plutôt que de donner une erreur sur le deuxième appel echoInnerBar () qui n'a pasinner_var
été défini.Les méthodes de classe fournissent un «sucre sémantique» (je ne sais pas si ce terme est largement utilisé) - ou «commodité sémantique».
Exemple: vous avez un ensemble de classes représentant des objets. Vous voudrez peut-être avoir la méthode de classe
all()
oufind()
écrireUser.all()
ouUser.find(firstname='Guido')
. Cela pourrait être fait en utilisant des fonctions de niveau module bien sûr ...la source
Ce qui vient de me frapper, venant de Ruby, est qu'une méthode dite de classe et une méthode dite d' instance sont juste une fonction avec une signification sémantique appliquée à son premier paramètre, qui est silencieusement transmise lorsque la fonction est appelée comme méthode de un objet (ie
obj.meth()
).Normalement, cet objet doit être une instance mais le
@classmethod
décorateur de méthode modifie les règles pour passer une classe. Vous pouvez appeler une méthode de classe sur une instance (c'est juste une fonction) - le premier argument sera sa classe.Parce que c'est juste une fonction , elle ne peut être déclarée qu'une seule fois dans une portée donnée (c'est-à-dire une
class
définition). Il s'ensuit donc, comme une surprise pour un Rubyist, que vous ne pouvez pas avoir une méthode de classe et une méthode d'instance du même nom .Considère ceci:
Vous pouvez faire appel
foo
à une instanceMais pas en classe:
Ajoutez maintenant
@classmethod
:L'appel à une instance passe désormais sa classe:
tout comme faire appel à une classe:
C'est seulement la convention qui dicte que nous utilisons
self
pour ce premier argument une méthode d'instance etcls
une méthode de classe. Je n'ai utilisé ni l'un ni l'autre ici pour illustrer que ce n'est qu'un argument. En Ruby,self
est un mot - clé.Contraste avec Ruby:
La méthode de classe Python n'est qu'une fonction décorée et vous pouvez utiliser les mêmes techniques pour créer vos propres décorateurs . Une méthode décorée enveloppe la méthode réelle (dans le cas où
@classmethod
elle passe l'argument de classe supplémentaire). La méthode sous-jacente est toujours là, cachée mais toujours accessible .note de bas de page: j'ai écrit ceci après qu'un conflit de noms entre une classe et une méthode d'instance a piqué ma curiosité. Je suis loin d'être un expert Python et j'aimerais avoir des commentaires si tout cela est faux.
la source
super()
). AFICT, la "magie" se produit lorsqu'un attribut est défini ou lu. L'appelobj.meth(arg)
en Python (contrairement à Ruby) signifie simplement(obj.meth)(arg)
. Rien n'est transmis silencieusement n'importe où,obj.meth
c'est juste un objet appelable qui accepte un argument de moins que la fonction à partir de laquelle il a été créé.obj.meth
, à son tour, signifie simplementgetattr(obj, "meth")
.C'est un sujet intéressant. Mon point de vue est que la méthode de classe python fonctionne comme un singleton plutôt qu'une usine (qui renvoie une instance produite d'une classe). La raison pour laquelle il s'agit d'un singleton est qu'il existe un objet commun qui est produit (le dictionnaire) mais une seule fois pour la classe mais partagé par toutes les instances.
Pour illustrer ceci, voici un exemple. Notez que toutes les instances ont une référence au dictionnaire unique. Ce n'est pas un modèle d'usine tel que je le comprends. C'est probablement très unique à python.
la source
Je me posais plusieurs fois la même question. Et même si les gars ici ont essayé de l'expliquer, à mon humble avis la meilleure réponse (et la plus simple) que j'ai trouvée est la description de la méthode Class dans la documentation Python.
Il est également fait référence à la méthode statique. Et dans le cas où quelqu'un connaît déjà les méthodes d'instance (ce que je suppose), cette réponse pourrait être la dernière pièce pour tout rassembler ...
Des explications plus approfondies sur ce sujet sont également disponibles dans la documentation: La hiérarchie des types standard (faites défiler jusqu'à la section Méthodes d'instance )
la source
@classmethod
peut être utile pour instancier facilement des objets de cette classe à partir de ressources externes. Considérer ce qui suit:Puis dans un autre fichier:
L'accès à inst.x donnera la même valeur que les paramètres ['x'].
la source
Une classe définit un ensemble d'instances, bien sûr. Et les méthodes d'une classe fonctionnent sur les instances individuelles. Les méthodes de classe (et les variables) permettent de suspendre d'autres informations liées à l'ensemble d'instances.
Par exemple, si votre classe définit un ensemble d'élèves, vous souhaiterez peut-être des variables ou des méthodes de classe qui définissent des éléments tels que l'ensemble de notes auquel les élèves peuvent appartenir.
Vous pouvez également utiliser des méthodes de classe pour définir des outils pour travailler sur l'ensemble complet. Par exemple, Student.all_of_em () peut renvoyer tous les étudiants connus. Évidemment, si votre ensemble d'instances a plus de structure qu'un simple ensemble, vous pouvez fournir des méthodes de classe pour connaître cette structure. Students.all_of_em (grade = 'juniors')
Des techniques comme celle-ci ont tendance à conduire au stockage des membres de l'ensemble d'instances dans des structures de données ancrées dans des variables de classe. Vous devez alors prendre soin d'éviter de frustrer la collecte des ordures.
la source