Wesh les mecs,
J ai rien compris la difference entre variable de classe et classmethod. Dans les deux cas il faut lier une methode à une instance. Jvois pas en quoi classmethod est plus global.
Wesh les mecs,
J ai rien compris la difference entre variable de classe et classmethod. Dans les deux cas il faut lier une methode à une instance. Jvois pas en quoi classmethod est plus global.
Salut,
Avec Python, tout est "attribut"... et la différence entre attribut et méthode est qu'une méthode est, à priori, un "callable" (mot plus générique que fonction appelable).
Quand on définit une classe, tous les attributs sont des attributs de classe:
et ils sont "de la classe" car accessibles par toutes les instances de la classe.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class A: toto = None def xyz(a, b, c): pass
Pour le reste, c'est de la ré-écriture.
Imaginons une instance de A nommée aa.
aa.xyz sera un objet de type "méthode" i.e. une fonction (A.xyz) associée à un objet (aa).
aa.xyz(...) sera un appel de la fonction A.xyz associée à l'objet aa avec les paramètres ...
Le boulot de l'interpréteur sera de savoir par quoi evremplacer le premier argument pour appeler la fonction:
- staticmethod: on laisse tel quel donc c'est l'appel de AA.xyz(...)
- classmethod: on ajoute la classe comme premier argument: AA.xyz(A, ...)
- methode normale: on ajoute l'instance: AA.xyz(aa,...)
Et l'intérêt de tout ce bazar est d'être consistant vis à vis de l'héritage.
- W
Dit-il l'index et le majeur levés en signe de victoire. Ok, salut à toi aussi...
Je pense (enfin j'espère) que c'est surtout l'utilité de l'instruction "classmethod" que tu n'as pas compris.
La classmethod récupère le type de l'objet qui l'invoque, ce qui permet de suivre l'évolution de ce type dans le cas d'un héritage (c'est alors le type hérité qui est récupéré)
Prenons un exemple simple : un objet permettant de manipuler une date…
L’utilisateur qui veut utiliser cet objet doit alors l’instancier selon une convention bien définie en lui passant les trois caractéristiques d’une date (jour, mois et année) en argument.
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 class date: def __init__(self, jj, mm, aa): self.jj=jj self.mm=mm self.aa=aa >>> a=date(1, 1, 2000) >>> print(a.jj, a.mm, a.aa) 1 1 2000
Si maintenant l’utilisateur recevait une date sous forme texte ("jj/mm/aaaa"), il devra alors éclater ce texte pour pouvoir récupérer ses divers éléments avant de pouvoir créer son objet.
Si ce comportement se généralise, il peut alors avoir envie de modifier son objet pour qu’il puisse absorber ou une date classique ou une date texte. Petit travail facile de factorisation qui, en retour, lui simplifiera ensuite grandement l’écriture du code qui utilisera cet objet.
Une première solution sera alors de modifier __init__() pour l’autoriser à absorber les deux types de paramètres. Faisable mais si demain un 3° format différent se présente, et un 4° après-demain…?
Une seconde solution sera de créer une méthode statique renvoyant un nouvel objet "date" :
L’avantage c’est que si un troisième format d’entrée arrive demain, on pourra toujours rajouter une autre méthode "fromXXX", "fromYYY" et ainsi de suite.
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 class date: def __init__(self, jj, mm, aa): self.jj=jj self.mm=mm self.aa=aa @staticmethod def fromString(string): (jj, mm, aa)=string.split("/") return date(jj, mm, aa) >>> a=date.fromString("1/1/2000") >>> print(a.jj, a.mm, a.aa) 1 1 2000
L’inconvénient c'est que la méthode utilise le nom de l’objet de façon littérale. Déjà cela induit des contraintes d’évolutivité (si le nom change demain…) et surtout peut poser des soucis liés à l’héritage (la méthode renvoie un objet "date" alors que l’utilisateur pourrait avoir envie d’utiliser un objet hérité de "date").
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class date: def __init__(self, jj, mm, aa): self.jj=jj self.mm=mm self.aa=aa @staticmethod def fromString(string): return date(*string.split("/")) class subDate(date): pass >>> a=date.fromString("1/1/2000") >>> type(a) <class '__main__.date'> >>> b=subDate.fromString("1/1/3000") >>> type(b) <class '__main__.date'> # Il voulait créer un subDate !!!
La troisième solution sera d’utiliser une fonction encapsulée dans une surcouche "classmethod()". Cette fonction recevra alors en premier paramètre le nom de la classe qui l’invoque (généralement on stocke ce nom dans un paramètre conventionnellement nommé "cls"). L’utilisateur pourra alors utiliser ce nom de classe pour générer l’objet qui en découle.
Cette solution répond aux mêmes contraintes que la solution précédente mais offre l’avantage de suivre l’évolution du code (si le nom de l’objet change, cela se fera de façon transparente sans avoir besoin de revérifier tout son contenu) ainsi que les contraintes liées à l'héritage.
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class date: def __init__(self, jj, mm, aa): self.jj=jj self.mm=mm self.aa=aa @classmethod def fromString(cls, string): return cls(*string.split("/")) >>> a=date.fromString("1/1/2000") >>> type(a) <class '__main__.date'>
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class date: def __init__(self, jj, mm, aa): self.jj=jj self.mm=mm self.aa=aa @classmethod def fromString(cls, string): return cls(*string.split("/")) class subDate(date): pass >>> a=date.fromString("1/1/2000") >>> type(a) <class '__main__.date'> >>> b=subDate.fromString("1/1/3000") >>> type(b) <class '__main__.subDate'> # Il a bien son objet subDate !!!
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Partager