web-dev-qa-db-fra.com

Python: Quand une variable est-elle passée par référence et quand par valeur?

Duplicata possible:
Python: Comment passer une variable par référence?

Mon code:

locs = [ [1], [2] ]
for loc in locs:
    loc = []

print locs
# prints => [ [1], [2] ]

Pourquoi loc n'est-il pas la référence des éléments de locs?

Python: Tout est passé comme référence à moins qu'il ne soit explicitement copié [N'est-ce pas vrai? ]

Veuillez expliquer .. comment python décide le référencement et la copie ?

Mise à jour:

Comment faire ?

def compute(ob):
   if isinstance(ob,list): return process_list(ob)
   if isinstance(ob,dict): return process_dict(ob)

for loc in locs:
   loc = compute(loc)  # What to change here to make loc a reference of actual locs iteration ?
  • les locs doivent contenir la réponse finale traitée!
  • Je ne veux pas utiliser enumerate, est-ce possible sans lui?
30
Yugal Jindle

Tout en Python est passé et assigné par valeur, de la même manière que tout est passé et assigné par valeur en Java. Chaque valeur en Python est une référence (pointeur) vers un objet. Les objets ne peuvent pas être des valeurs. L'affectation copie toujours la valeur (qui est un pointeur); deux de ces pointeurs peuvent donc pointer vers le même objet. Les objets ne sont jamais copiés sauf si vous faites quelque chose d'explicite pour les copier.

Pour votre cas, chaque itération de la boucle assigne un élément de la liste dans la variable loc. Vous affectez ensuite autre chose à la variable loc. Toutes ces valeurs sont des pointeurs; vous attribuez des pointeurs; mais vous n'affectez aucun objet en aucune façon.

23
newacct

Effbot (alias Fredrik Lundh) a décrit le style de passage des variables de Python comme un appel par objet: http://effbot.org/zone/call-by-object.htm

Les objets sont alloués sur le tas et les pointeurs vers eux peuvent être transmis n'importe où.

  • Lorsque vous effectuez une affectation telle que x = 1000, Une entrée de dictionnaire est créée qui mappe la chaîne "x" dans l'espace de noms actuel vers un pointeur sur l'objet entier contenant mille.
  • Lorsque vous mettez à jour "x" avec x = 2000, Un nouvel objet entier est créé et le dictionnaire est mis à jour pour pointer vers le nouvel objet. L'ancien objet mille est inchangé (et peut être vivant ou non selon que quelque chose d'autre se réfère à l'objet).
  • Lorsque vous effectuez une nouvelle affectation telle que y = x, Une nouvelle entrée de dictionnaire "y" est créée qui pointe vers le même objet que l'entrée pour "x".
  • Les objets comme les chaînes et les entiers sont immuables . Cela signifie simplement qu'aucune méthode ne peut modifier l'objet après sa création. Par exemple, une fois l'objet entier mille créé, il ne changera jamais. Les mathématiques sont effectuées en créant de nouveaux objets entiers.
  • Les objets comme les listes sont mutables . Cela signifie que le contenu de l'objet peut être modifié par tout élément pointant vers l'objet. Par exemple, x = []; y = x; x.append(10); print y affichera [10]. La liste vide a été créée. "X" et "y" pointent tous deux vers la même liste. La méthode append mute (met à jour) l'objet liste (comme l'ajout d'un enregistrement à une base de données) et le résultat est visible à la fois par "x" et "y "(tout comme une mise à jour de la base de données serait visible pour chaque connexion à cette base de données).

J'espère que cela clarifie le problème pour vous.

52
Raymond Hettinger

Il n'est pas utile dans Python de penser en termes de références ou de valeurs. Ni l'un ni l'autre n'est correct.

En Python, les variables ne sont que des noms. Dans votre boucle for, loc est juste un nom qui pointe vers l'élément courant dans la liste. Faire loc = [] simplement relie le nom loc à une autre liste, laissant la version originale seule.

Mais puisque dans votre exemple, chaque élément est une liste, vous pouvez réellement muter cet élément, et cela se refléterait dans la liste d'origine:

for loc in locs:
    loc[0] = loc[0] * 2
8
Daniel Roseman

Quand tu dis

loc = []

vous reliez la variable loc à une liste vide nouvellement créée

Peut-être que tu veux

loc[:] = []

Qui attribue une tranche (qui se trouve être la liste entière) de loc à la liste vide

5
John La Rooy

Tout passe par objet. La reliure et la mutation sont des opérations différentes.

locs = [ [1], [2] ]
for loc in locs:
    del loc[:]

print locs
2

Pourquoi loc ne fait-il pas référence à des éléments de locs?

C'est. Ou du moins, c'est dans le même sens que toutes les autres variables de Python est. Python sont noms, pas de stockage . loc est un nom utilisé pour faire référence aux éléments de [[1,2], [3,4]], tandis que locs est un nom qui fait référence à la structure entière.

loc = []

Cela ne veut pas dire "regardez la chose que loc nomme, et la transforme en [] ". Cela ne peut pas signifie que, parce que Python sont pas capables d'une telle chose.

Au lieu de cela, cela signifie "faire en sorte que loc cesse d'être un nom pour la chose pour laquelle il s'agit actuellement d'un nom, et commence à la place comme un nom pour [] ". (Bien sûr, cela signifie que le [] qui y est fourni, car en général il peut y avoir plusieurs objets en mémoire qui sont identiques.)

Naturellement, le contenu de locs est inchangé en conséquence.

2
Karl Knechtel