Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

Complément - niveau intermédiaire

Entre le code qui appelle une fonction et le code de la fonction elle-même

def ma_fonction(dans_fonction):
    print(dans_fonction)
    
dans_appelant = ["texte"]
ma_fonction(dans_appelant)
['texte']

on peut se demander quelle est exactement la nature de la relation entre l’appelant et l’appelé, c’est-à-dire ici dans_appelant et dans_fonction.

C’est l’objet de ce complément.

Passage par valeur - passage par référence

Si vous avez appris d’autres langages de programmation comme C ou C++, on a pu vous parler de deux modes de passage de paramètres :

Python fait du passage par référence

Certains langages comme Pascal - et C++ si on veut - proposent ces deux modes. En Python, tous les passages de paramètres se font par référence.

# chargeons la magie pour pythontutor
%load_ext ipythontutor
%%ipythontutor curInstr=4
def ma_fonction(dans_fonction):
    print(dans_fonction)
    
dans_appelant = ["texte"]
ma_fonction(dans_appelant)
Loading...

Ce qui signifie qu’on peut voir le code ci-dessus comme étant - pour simplifier - équivalent à ceci :

dans_appelant = ["texte"]

# ma_fonction (dans_appelant)
# → on entre dans la fonction
dans_fonction = dans_appelant
print(dans_fonction)
['texte']

On peut le voir encore d’une autre façon en instrumentant le code comme ceci -- on rappelle que la fonction built-in id retourne l’adresse mémoire d’un objet :

def ma_fonction(dans_fonction):
    print('dans ma_fonction', dans_fonction , id(dans_fonction))
    
dans_appelant = ["texte"]
print('dans appelant   ', dans_appelant, id(dans_appelant))
ma_fonction(dans_appelant)
dans appelant    ['texte'] 140485505723776
dans ma_fonction ['texte'] 140485505723776

Des références partagées

On voit donc que l’appel de fonction crée des références partagées, exactement comme l’affectation, et que tout ce que nous avons vu au sujet des références partagées s’applique exactement à l’identique :

# on ne peut pas modifier un immuable dans une fonction
def increment(n):
    n += 1

compteur = 10
increment(compteur)
print(compteur)
10
# on peut par contre ajouter dans une liste
def insert(liste, valeur):
    liste.append(valeur)
    
liste = ["un"]
insert(liste, "texte")
print(liste)
['un', 'texte']

Pour cette raison, il est important de bien préciser, quand vous documentez une fonction, si elle fait des effets de bord sur ses arguments (c’est-à-dire qu’elle modifie ses arguments), ou si elle produit une copie. Rappelez-vous par exemple le cas de la méthode sort sur les listes, et de la fonction de commodité sorted, que nous avions vues en semaine 2.

De cette façon, on saura s’il faut ou non copier l’argument avant de le passer à votre fonction.