Il s'agit d'un passage par valeur, où toutes les valeurs sont des pointeurs vers des objets. On pourrait penser que cela implique que l'on peut utiliser le pointeur passé pour modifier la variable de l'appelant, ce qui en fait un passage par référence, mais ce n'est pas le cas, donc ce n'est pas le cas.
Pour comprendre comment fonctionne le passage de valeurs en Python, il est essentiel de savoir qu'il n'existe pas de valeurs "non encadrées" (sans objet). Les entiers sont des objets, et une variable qui "contient" un entier est en fait un pointeur vers un objet entier stocké ailleurs que dans la variable. Il en va de même pour les flottants et les booléens.
En Python, les variables ne "détiennent" pas vraiment de valeurs comme c'est le cas, par exemple, en C. L'affectation consiste donc toujours à faire pointer le nom de la variable vers un objet différent.
Si un objet transmis à une fonction est mutable, la fonction peut le modifier, mais elle doit le faire sans changer l'objet vers lequel son ou ses noms pointent. Par exemple :
some_digits_of_pi = [3, 1, 4, 1, 5, 9, 2, 7]
def extend_pi(x):
x[-1] = 6
x += [5, 3, 5, 9]
Il s'agit ici d'une mutation x
à l'intérieur de la fonction. (Pour une liste, +=
est essentiellement list.extend
.) Puisque x
n'est jamais modifié pour pointer vers un objet différent, les modifications sont apportées à la liste qui a été transmise. Le nom some_digits_of_pi
fait référence au même objet que celui qui est modifié dans la fonction, de sorte que l'appelant verra que sa liste de ce nom a été modifiée.
Si l'on écrit x = [2, 7, 1, 8, 2, 8, 1, 8]
à la fin de la fonction, cela créerait un nouvel objet liste et pointerait le nom local x
à ce sujet. Cela ne change pas ce que la variable de l'appelant pointe vers, donc cette liste n'est pas modifiée par cette déclaration.
En d'autres termes, vous ne pouvez pas faire de la de l'appelant variable ( some_digits_of_pi
dans ce cas) pointent vers un objet différent. Si vous modifiez x
pour pointer vers un objet différent à l'intérieur de la fonction, seulement x
pointe vers cet objet.
Les nombres, les chaînes de caractères, les tuples et autres fonctionnent exactement de la même manière. Un pointeur sur l'objet est transmis ; si vous modifiez la valeur de l'argument à l'intérieur de la fonction, il est amené à pointer sur un objet différent, ce qui ne modifie naturellement pas la variable de l'appelant. Il s'agit seulement d'une modification de la variable de l'appelant. semble parce que ces types d'objets ne sont pas mutables et qu'il n'existe aucun moyen de les modifier sur place.
Un autre point de confusion réside dans le fait qu'il regards comme int
et list
ont tous deux +=
mais il arrive que +=
sur un int
fait quelque chose de très différent de ce que la même opération fait sur un list
. Sur une liste, +=
renvoie le même objet liste (modifié), alors que sur un entier, il peut renvoyer un objet complètement différent (puisque les entiers sont immuables).