Que sont les «méthodes de classe» et les «méthodes d'instance» en Python?

37

Il y a eu une discussion en discussion relative à une question (la question elle-même étant sans rapport avec celle-ci), qui a révélé que je ne connaissais peut-être pas Python.

Dans mon esprit, bien que la terminologie diffère d'une langue à l'autre, nous pouvons généralement classer les fonctions comme suit:

  • [libre] fonctions
  • méthodes statiques / fonctions membres static
  • méthodes non statiques / fonctions membres non statiques

Apparemment, en Python, il existe un autre type de fonction qui ne rentre pas dans les catégories ci-dessus, celle qui est une méthode mais "ne connaît pas sa classe".

Que sont les "méthodes de classe" et les "méthodes d'instance", en Python?

Courses de légèreté avec Monica
la source
1
Si vous êtes intéressé par une discussion en ligne, commencez ici: chat.stackexchange.com/transcript/message/26479002#26479002
yannis
1
OMI une meilleure réponse est fournie par un autre site web stackexchange: stackoverflow.com/questions/136097/…
Trevor Boyd Smith
Pour info, le lien est fourni au bas de la page acceptée ... mais je pense que beaucoup de gens vont rater le lien ou ne l’atteindre jamais et j’ai donc copié le lien ici.
Trevor Boyd Smith

Réponses:

49

La réponse courte

  • une méthode d'instance connaît son instance (et de là sa classe)
  • une méthode de classe connaît sa classe
  • une méthode statique ne connaît pas sa classe ou son instance

La longue réponse

Méthodes de classe

Une méthode de classe est une méthode qui appartient à la classe dans son ensemble. Cela ne nécessite pas d'instance. Au lieu de cela, la classe sera automatiquement envoyée en tant que premier argument. Une méthode de classe est déclarée avec le @classmethoddécorateur.

Par exemple:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Méthodes d'instance

D'autre part, une méthode d'instance nécessite une instance pour l'appeler et ne nécessite aucun décorateur. C'est de loin le type de méthode le plus courant.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(note: ce qui précède est avec python3; avec python2, vous obtiendrez une erreur légèrement différente)

Méthodes statiques

Une méthode statique est similaire à une méthode de classe, mais n'obtiendra pas l'objet de classe en tant que paramètre automatique. Il est créé en utilisant le @staticmethoddécorateur.

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Liens de documentation

Voici des liens vers la documentation python3 pertinente:

La documentation du modèle de données a ceci à dire sur la différence entre les méthodes de classe et les méthodes statiques:

Objets de méthode statiques Les objets de méthode statiques permettent de contourner la transformation d'objets de fonction en objets de méthode décrits ci-dessus. Un objet méthode statique est une enveloppe autour de tout autre objet, généralement un objet méthode défini par l'utilisateur. Lorsqu'un objet de méthode statique est extrait d'une classe ou d'une instance de classe, l'objet renvoyé est l'objet enveloppé, qui n'est soumis à aucune autre transformation. Les objets de méthode statique ne sont pas eux-mêmes appelables, bien que les objets qu'ils enveloppent le soient habituellement. Les objets de méthode statiques sont créés par le constructeur staticmethod () intégré.

Objets de méthode de classe Un objet de méthode de classe, comme un objet de méthode statique, est un wrapper autour d'un autre objet qui modifie la manière dont cet objet est extrait des classes et des instances de classe. Le comportement des objets de méthode de classe lors d'une telle récupération est décrit ci-dessus, sous «Méthodes définies par l'utilisateur». Les objets de méthode de classe sont créés par le constructeur intégré classmethod ().

Questions connexes

Bryan Oakley
la source
4
@LightnessRacesinOrbit: Je ne pense pas que les méthodes statiques soient utilisées particulièrement souvent en python. En utilisant mon système comme échantillon aléatoire, lorsque je recherche dans tous les packages que j'ai installés, environ 1% seulement des méthodes utilisées sont des méthodes statiques (ce qui, franchement, était supérieur à ce à quoi je m'attendais).
Bryan Oakley
1
Les "méthodes statiques" sont généralement une odeur de code et sont déconseillées, par exemple, par le guide de style Gogole Python.
9000
3
Je pense que la réponse serait meilleure si elle attirait l’attention sur les sous-classes, qui permettent aux méthodes de classe d’être utiles.
Winston Ewert
1
@ user2357112: J'ai simplement compté toutes les instances de "^ def(", puis toutes les instances de @staticmethod. Très peu scientifique, mais probablement dans les limites du stade.
Bryan Oakley
2
@Kashyap: le TL; DR s'applique au tout premier paragraphe. Je pense que ça marche mieux en haut qu'en bas.
Bryan Oakley
8

Que sont les «méthodes de classe» et les «méthodes d'instance» en Python?

  • Une "méthode d'instance" utilise les informations contenues dans l'instance pour déterminer la valeur à renvoyer (ou l'effet secondaire à effectuer). Ce sont très communs.

  • Une "méthode de classe" utilise des informations sur la classe (et non une instance de cette classe) pour affecter son action (elles sont généralement utilisées pour créer de nouvelles instances en tant que constructeurs alternatifs et ne sont donc pas incroyablement communes).

  • Une "méthode statique" n'utilise aucune information sur la classe ou l'instance pour calculer ce qu'elle fait. C'est généralement juste dans la classe pour plus de commodité. (En tant que tels, ils ne sont pas très courants non plus.)

Une fonction de X

Rappelez-vous la classe de mathématiques, "y est une fonction de x f(x),?" Appliquons cela dans le code:

y = function(x)

Ce qui est supposé par ce qui précède est que depuis xpeut changer, ypeut changer lorsque des xchangements C’est ce que l’on entend par " yfonction de x"

Qu'est - ce qui yest quand zest 1? 2? 'FooBarBaz'?

yn'est pas une fonction de z, donc zpeut être n'importe quoi et ne pas affecter le résultat de la fonction en supposant que notre fonction functionest pure. (Si elle accède en ztant que variable globale, alors ce n'est pas une fonction pure - c'est ce que l'on entend par pureté fonctionnelle.)

Gardez ce qui précède à l’esprit lorsque vous lisez les descriptions suivantes:

Méthodes d'instance

Une méthode d'instance est une fonction qui est une fonction d' une instance . La fonction accepte implicitement l'instance en tant qu'argument et l'instance est utilisée par la fonction pour déterminer la sortie de la fonction.

Un exemple intégré d'une méthode d'instance est str.lower:

>>> 'ABC'.lower()
'abc'

str.lower est appelé sur l'instance de la chaîne et utilise les informations contenues dans l'instance pour déterminer la nouvelle chaîne à renvoyer.

Méthodes de classe:

Rappelez-vous, en Python, tout est un objet. Cela signifie que la classe est un objet et peut être transmise comme argument à une fonction.

Une méthode de classe est une fonction qui est une fonction de la classe . Il accepte la classe comme argument.

Un exemple intégré est dict.fromkeys:

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

La fonction connaît implicitement sa propre classe. Elle utilise la classe pour affecter la sortie de la fonction et crée une nouvelle classe de cette classe à partir de l'itérable. OrderedDict le démontre en utilisant la même méthode:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

La méthode class utilise des informations sur la classe (et non une instance de cette classe) pour affecter le type de classe à renvoyer.

Méthodes statiques

Vous mentionnez une méthode qui "ne connaît pas sa classe" - il s'agit d'une méthode statique en Python. Il est simplement attaché par commodité à l'objet de classe. Il pourrait éventuellement s'agir d'une fonction distincte dans un autre module, mais sa signature d'appel serait la même.

Une méthode statique n'est une fonction ni de la classe ni de l'objet.

Str.maketrans de Python 3 est un exemple intégré de méthode statique.

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

À partir de quelques arguments, il crée un dictionnaire qui n'est pas une fonction de sa classe.

C'est pratique car il strest toujours disponible dans l'espace de noms global, vous pouvez donc l'utiliser facilement avec la fonction de traduction:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

En Python 2, vous devez y accéder depuis le stringmodule:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Exemple

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

Instancions:

>>> instance = AClass()

Maintenant, l'instance peut appeler toutes les méthodes:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

Mais la classe n'est généralement pas destinée à appeler la méthode d'instance, bien qu'elle soit appelée aux autres:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

Vous devez explicitement passer l'instance pour appeler la méthode d'instance:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)
Aaron Hall
la source
"C’est une méthode statique en Python. Elle est simplement attachée par commodité à l’objet class. Elle pourrait éventuellement être une fonction distincte dans un autre module, mais sa signature d’appel serait la même." Semble plus déroutant que pratique. Pourquoi voudriez-vous attacher une fonction à une classe si son corps n'aura aucune notion de cette classe.
Courses de légèreté avec Monica
@LightnessRacesinOrbit J'ai élaboré sur chaque point
Aaron Hall
Personnellement, j'ai toujours considéré qu'une méthode d'instance est une opération sur une instance particulière, une méthode de classe est une sorte de constructeur (pour des raisons de commodité, rien de semblable, MyClass(1,2,3)mais plutôt, comme MyClass.get_special(1,2,3)), et une méthode statique être une fonction normale qui pourrait rester seule de toute façon.
Zizouz212
Oui, les méthodes de classe sont généralement utilisées pour les constructeurs alternatifs (voir mon exemple dict.fromkeys ci-dessus, ainsi que le code source pandas.DataFrame), mais ce n'est pas une caractéristique déterminante. Parfois, j'ai simplement besoin d'accéder aux données stockées au niveau de la classe à partir d'une méthode, sans accéder à l'instance. Si vous appelez le type (self) (ou pire, self .__ class__) et que vous n'utilisez pas self directement dans une méthode d'instance, c'est un bon signe que vous devriez considérer qu'il s'agit d'une méthode de classe. Comme les méthodes de classe ne nécessitent pas d'instances, cela les rend plus faciles à analyser.
Aaron Hall
4
  • Une "méthode d'instance" est une méthode qui obtient l'objet instance en tant que premier paramètre appelé par convention self. C'est la valeur par défaut.

  • Une "méthode statique" est une méthode sans selfparamètre initial . Ceci est mis en œuvre avec le décorateur @staticmethod .

  • Une "méthode de classe" est une méthode dans laquelle le paramètre initial n'est pas un objet d'instance, mais un objet de classe ( voir cette partie de la documentation Python pour connaître ce qu'est un "objet de classe"), appelé par convention cls. Ceci est mis en œuvre avec le décorateur @classmethod .

L'utilisation typique du terme "méthode statique" dans C / C ++ / etc s'applique aux méthodes Python "statique" et Python "classe", car ces deux types de méthodes ne font pas référence à l'instance. En C / C ++ / etc, les méthodes ont normalement un accès implicite à tous les membres / méthodes de la classe ne faisant pas d’instance, ce qui explique probablement pourquoi cette distinction n’existe que dans des langages tels que Python / Ruby / etc.

Ixrec
la source
Une méthode statique en C / C ++ a-t-elle une référence à l'objet de classe? Ou simplement "membres" de la classe? Peuvent-ils créer de nouveaux membres de la classe? :)
Aaron Hall
3
@AaronHall En C / C ++, il n'existe pas d'objet de classe et vous n'avez pas besoin de référence pour appeler des méthodes statiques. Vous écrivez juste Class::staticMethod()et c'est tout (tant que vous n'êtes pas interdit d'appeler parce que staticMethod()c'est privé ou quelque chose comme ça).
Ixrec