Une méthode en Python : la fonction rattachée à un objet

Une méthode est une fonction définie dans une classe et rattachée à un objet. Le rôle de self, les quatre familles et les pièges d'appel.
5 min de lecture
Believemy logo

Définition

Imaginez une fonction qui calcule le total d'un panier. Elle a besoin de connaître les articles du panier, alors on les lui passe en argument. Le souci commence quand plusieurs fonctions partagent ce même panier : chacune réclame les mêmes informations, et un oubli de paramètre suffit à créer un bug invisible à la lecture.

Une méthode répond à cet ennui en attachant la fonction à l'objet. C'est une fonction définie dans une classe et rattachée à ses objets, avec le même def qu'une fonction ordinaire : son premier paramètre reçoit l'objet appelant et porte par convention le nom self.

Voici à quoi cela ressemble une fois posé dans une classe.

PYTHON
class Panier:
    def __init__(self):
        self.articles = []

    def ajouter(self, article):
        self.articles.append(article)

panier = Panier()
panier.ajouter("clavier")

Regardez le décalage entre la déclaration et l'appel : ajouter attend deux paramètres, self et article, mais on ne lui en donne qu'un seul. Le point qui précède ajouter fait le travail manquant, en indiquant à Python quel objet doit remplir self. panier.ajouter("clavier") revient exactement à Panier.ajouter(panier, "clavier"), rien de plus.


Ce que change le fait d'attacher la fonction à l'objet

Pourquoi s'imposer ce détour plutôt que d'écrire des fonctions ordinaires ? La réponse tient à la mémoire : une fonction reçoit ses données à chaque appel, une méthode vit avec elles en permanence, sous la forme des attributs de l'objet. Elle lit et modifie chaque attribut de son objet sans argument supplémentaire.

Comparez les deux écritures suivantes pour vous en convaincre.

PYTHON
# Sans méthode : chaque fonction réclame les mêmes arguments
def ajouter(articles, article):
    articles.append(article)

def total(articles, prix):
    return sum(prix[a] for a in articles)

# Avec méthode : les données sont déjà attachées à l'objet
class Panier:
    def ajouter(self, article):
        self.articles.append(article)

Sur un script de trente lignes, la première forme suffit largement. La différence se sent dès qu'un même paquet de données circule entre plusieurs fonctions, où une inversion de paramètres passe inaperçue jusqu'au bug. La méthode range tout ce qui concerne le panier au même endroit, ce qui rend l'erreur d'appel presque impossible. C'est d'abord un choix d'organisation, avant d'être un choix technique.


Les quatre familles de méthodes

Toutes les méthodes ne reçoivent pas self de la même façon, et c'est précisément ce qui permet de les ranger en quatre familles, résumées dans le tableau suivant.

FamillePremier paramètreCe qu'elle sert à faire
Méthode d'instanceself, l'objetLire ou modifier une instance précise
classmethodcls, la classeConstruire un objet autrement que par __init__
staticmethodAucunRanger un utilitaire près de la classe qui s'en sert
méthode magiqueself, l'objetDonner un comportement natif : addition, affichage, longueur

La première famille couvre l'essentiel du quotidien, et un débutant qui ne connaît qu'elle écrit déjà du code parfaitement correct. Les deux suivantes se repèrent à l'arobase posé au-dessus du def. La dernière se reconnaît à ses deux paires de traits bas, comme __init__, et sert à brancher un objet sur les opérateurs natifs de Python.


Le piège de la méthode qui ne renvoie rien

Un embêtement classique survient quand on enchaîne les méthodes comme des fonctions ordinaires. Beaucoup de méthodes de la bibliothèque standard modifient l'objet sur place et renvoient None, parce qu'elles n'ont rien de plus utile à renvoyer : l'objet a déjà été changé.

PYTHON
noms = ["zoe", "adam", "lea"]

# Trie la liste en place et renvoie None : rien à récupérer ici
resultat = noms.sort()

# Construit une nouvelle liste triée, sans toucher à l'originale
resultat = sorted(noms)
Attention

Le bug qui suit ne se déclenche jamais sur la ligne noms.sort(). Il attend une ligne plus loin, quand une AttributeError annonce que None ne possède pas la méthode demandée.

Retenez un repère simple : ce qui agit sur l'objet en place renvoie None, ce qui construit un résultat le renvoie. sort() trie la liste existante sans rien rendre, sorted() construit une liste neuve et la renvoie.


Redéfinir une méthode héritée

Que se passe-t-il quand une classe fille doit se comporter presque comme sa classe mère, mais pas tout à fait ? Une classe fille reçoit les méthodes de sa mère par héritage et peut en réécrire une sous le même nom.

PYTHON
class Client:
    def remise(self):
        return 0

class ClientFidele(Client):
    def remise(self):
        return super().remise() + 10

Python retient toujours la version la plus proche de l'objet : si ClientFidele définit sa propre méthode remise, c'est elle qui s'exécute, jamais celle de Client. Pour ne pas recopier ce que la classe mère fait déjà, super permet d'appeler sa version depuis la classe fille et de compléter seulement ce qu'il faut.

C'est ici qu'une méthode se distingue d'une fonction ordinaire. Son nom ne désigne plus un bloc de code figé, mais celui que l'objet apporte avec lui. Deux objets différents, appelés par la même ligne objet.remise(), exécutent deux corps différents, sans que le code appelant sache lequel des deux se déclenche.


Questions fréquentes

Question

Quelle est la différence entre une méthode et une fonction ?

Une fonction existe seule et reçoit en argument tout ce dont elle a besoin. Une méthode appartient à une classe et reçoit en plus l'objet sur lequel on l'appelle, ce qui lui donne accès à son état sans paramètre supplémentaire.

Question

Faut-il vraiment écrire self dans chaque définition ?

Oui, pour une méthode d'instance. Python le fournit automatiquement au moment de l'appel, mais il n'apparaît pas tout seul dans la signature : c'est à vous de l'y écrire. L'oublier produit un message d'erreur sur le nombre d'arguments, toujours un de plus que prévu, et c'est souvent la toute première erreur que rencontrent les débutants.

Question

Comment savoir quelles méthodes possède un objet ?

La fonction dir(objet) en donne la liste complète, traits bas compris, et help(objet) y ajoute les explications rédigées par l'auteur de la classe. Notre formation Python aborde les classes une fois les fonctions acquises, parce qu'une méthode ne prend son sens qu'à ce moment-là.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.