web-dev-qa-db-fra.com

python passé en entrée d'une fonction agit comme un global dans cette fonction plutôt que comme un local

Je suis très confus par le comportement ci-dessous. Les cas 1, 3 et 4 fonctionnent comme je m'y attendais, mais pas le cas 2. Pourquoi le cas 2 permet-il à la fonction de modifier la valeur de l'entrée de dictionnaire globalement, même si le dictionnaire n'est jamais renvoyé par la fonction? Une raison principale pour laquelle j'utilise des fonctions est d'isoler tout ce qui se trouve dans la fonction du reste du code, mais cela ne semble pas être possible si je choisis d'utiliser les mêmes noms de variables à l'intérieur de la fonction. J'étais sous la compréhension que tout ce qui est explicitement défini dans une fonction est local à cette fonction, mais cela ne semble pas être le cas si le dictionnaire est défini et passé en entrée de la fonction .

Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.

============= Cas 1 ===============

>>> def testfun1(a):
...     a=2
... 
>>> a=0
>>> testfun1(a)
>>> a
0

============= Cas 2 ===============

>>> def testfun2(b):
...     b['test']=2
... 
>>> b={}
>>> testfun2(b)
>>> b
{'test': 2}

============= Cas 3 ===============

>>> def testfun3():
...     c=2
... 
>>> c=0
>>> testfun3()
>>> c
0

============= Cas 4 =============== (expliqué par cette question: les dictionnaires globaux n'ont pas besoin de mot-clé global pour modifier eux? )

>>> def testfun4():
...     d['test']=10
... 
>>> d={}
>>> testfun4()
>>> d
{'test': 10}
34
user1748155

Le passage des paramètres de Python agit un peu différemment des langages auxquels vous êtes probablement habitué . Au lieu d'avoir une sémantique explicite de passage par valeur et de passage par référence, python a passe par nom. Vous passez essentiellement toujours l'objet lui-même, et la mutabilité de l'objet détermine s'il peut ou non être modifié. Les listes et les dictés sont des objets modifiables, contrairement aux nombres, aux chaînes et aux tuples.

Vous passez le dictionnaire à la fonction, pas une copie. Ainsi, lorsque vous le modifiez, vous modifiez également la copie d'origine.

Pour éviter cela, vous devez d'abord copier le dictionnaire avant d'appeler la fonction, ou à partir de la fonction (passer le dictionnaire à la fonction dict devrait le faire).

77
Casey Kuball

Pour prendre en charge ce que @ Casey Kuball a dit, chaque objet dans Python est passé par référence. Chaque fonction reçoit une référence à l'objet réel que vous avez passé. La modification de ces objets dépend de s'il s'agit de types de données mutables.

En substance, on peut dire que les objets mutables comme dict, set et list sont passés par référence. Les objets immuables comme int, str, Tuple sont passés par valeur.

Il ne faut pas non plus qu'il y ait des cas où des objets modifiables sont remplacés dans une fonction, perdant ainsi la référence à l'objet réel transmis à la fonction.

>>> def testfun(b):
...     b = b or {}  # Creates a new object if b is false
...     b['test'] = 2
... 
>>> b = {}
>>> testfun(b)
>>> b
{}
1
Chuma Umenze

Le mot-clé global est requis uniquement pour l'affectation (et probablement del, je ne l'ai jamais essayé). Les mutations d'objets sont parfaitement valides.

1
Demian Brecht

Vous avez passé un objet dict à la fonction et l'avez modifié à l'intérieur de la fonction, donc bien sûr il sera modifié après le retour de la fonction. L'objet n'est pas copié, vous modifiez donc le même objet que vous avez passé, et cette question n'a rien à voir avec la dénomination, les noms similaires, les étendues, etc. lorsque vous avez passé l'objet explicitement.

0
wRAR

Lorsque vous passez un objet de base comme un entier ou une chaîne à une fonction, si vous le changez à l'intérieur de la fonction, rien ne se produit à l'objet correspondant en dehors de la fonction parce que lorsque vous menez avec un objet de base, python passe en valeur.

Cependant, si vous passez un dictionnaire ou une liste à une fonction, ils sont passés par référence, ce qui signifie que vous aurez ce comportement: l'objet en dehors de la fonction est modifié, comme vous l'avez vu.

edit: De plus, il y a une différence entre passer par valeur ou par référence: par valeur, une "copie" de l'objet est faite afin d'être utilisé dans la fonction; par référence, le même objet est passé par référence et les modifications apportées à l'intérieur de la fonction sont visibles à l'extérieur. Par définition python passe ses objets immuables par valeur et ses objets mutables par référence.

0
sissi_luaty