108 votes

Fonctions Python appelées par référence

Dans certains langages, vous pouvez transmettre un paramètre par référence ou par valeur en utilisant un mot réservé spécial comme réf. o val . Lorsque vous passez un paramètre à une fonction Python, celle-ci ne modifie jamais la valeur du paramètre lorsqu'elle quitte la fonction. mondial mot réservé (ou tel que je le comprends actuellement).

Exemple 1 :

k = 2

def foo (n):
     n = n * n     #clarity regarding comment below
     square = n
     return square

j = foo(k)
print j
print k

montrerait

>>4
>>2

montrant que k est inchangé.

Dans cet exemple, la variable n n'est jamais modifiée

Exemple 2 :

n = 0
def foo():
    global n
    n = n * n
    return n

Dans cet exemple, la variable n est modifiée.

Existe-t-il un moyen dans Python d'appeler une fonction et de dire à Python que le paramètre est soit une valeur o référence au lieu d'utiliser le paramètre global ?

Deuxièmement, dans les examens de Cambridge de niveau A, on dit maintenant qu'une fonction renvoie un simple alors qu'une procédure renvoie une valeur plus d'un valeur. Dans les années 80, on m'a appris qu'une fonction avait une déclaration de retour et qu'une procédure n'en avait pas. Pourquoi est-ce maintenant incorrect ?

219voto

Shobhit Verma Points 2096

Il existe essentiellement trois types d'"appels de fonction" :

  • Passe par valeur
  • Passer par référence
  • Passage par référence d'objet

Python est un langage de programmation PASS-BY-OBJECT-REFERENCE.

Tout d'abord, il est important de comprendre qu'une variable et la valeur de la variable (l'objet) sont deux choses distinctes. La variable "pointe" vers l'objet. La variable n'est pas l'objet. Encore une fois :

LA VARIABLE N'EST PAS L'OBJET

Exemple : dans la ligne de code suivante :

>>> x = []

[] est la liste vide, x est une variable qui pointe vers la liste vide, mais x n'est pas la liste vide.

Considérons la variable ( x dans le cas ci-dessus) comme une case, et "la valeur" de la variable ( [] ) comme l'objet à l'intérieur de la boîte.

PASS BY OBJECT REFERENCE (Cas en python) :

Ici, "les références d'objets sont passées par valeur".

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x

Ici, la déclaration x = [0] fait une variable x (boîte) qui pointe vers l'objet [0] .

Lors de l'appel de la fonction, une nouvelle boîte li est créé. Le contenu de li sont les mêmes que le contenu de la boîte. x . Les deux boîtes contiennent le même objet. C'est-à-dire que les deux variables pointent vers le même objet en mémoire. Par conséquent, toute modification de l'objet pointé par la variable li sera également réfléchi par l'objet pointé par x .

En conclusion, le résultat du programme ci-dessus sera :

[0, 1]

Note :

Si la variable li est réaffecté dans la fonction, alors li pointera vers un objet distinct en mémoire. x continuera cependant à pointer vers le même objet en mémoire que celui qu'il pointait auparavant.

Exemple :

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x

La sortie du programme sera :

[0]

PASSER PAR RÉFÉRENCE :

La boîte de la fonction appelante est transmise à la fonction appelée. Implicitement, le contenu de la boîte (la valeur de la variable) est transmis à la fonction appelée. Par conséquent, toute modification du contenu de la boîte dans la fonction appelée sera reflétée dans la fonction appelante.

PASS BY VALUE :

Une nouvelle boîte est créée dans la fonction appelée, et copies du contenu de la boîte de la fonction appelante est stocké dans les nouvelles boîtes.

J'espère que cela vous aidera.

88voto

dave mankoff Points 3837

Vous ne pouvez pas modifier un objet immuable, tel que str o tuple à l'intérieur d'une fonction en Python, mais vous pouvez faire des choses comme :

def foo(y):
  y[0] = y[0]**2

x = [5]
foo(x)
print x[0]  # prints 25

C'est toutefois une façon bizarre de procéder, à moins que vous n'ayez besoin de toujours mettre au carré certains éléments d'un tableau.

Notez qu'en Python, vous pouvez également renvoyer plus d'une valeur, ce qui rend moins importants certains des cas d'utilisation de la méthode pass by reference :

def foo(x, y):
   return x**2, y**2

a = 2
b = 3
a, b = foo(a, b)  # a == 4; b == 9

Lorsque vous renvoyez des valeurs de ce type, elles sont renvoyées sous la forme d'un Tuple qui est à son tour décomposé.

éditer : Une autre façon de voir les choses est que, bien que vous ne puissiez pas explicitement passer des variables par référence en Python, vous pouvez modifier les propriétés des objets qui ont été passés. Dans mon exemple (et d'autres), vous pouvez modifier les membres de la liste qui a été transmise. En revanche, vous ne pouvez pas réaffecter entièrement la variable transmise. Par exemple, les deux morceaux de code suivants semblent faire quelque chose de similaire, mais aboutissent à des résultats différents :

def clear_a(x):
  x = []

def clear_b(x):
  while x: x.pop()

z = [1,2,3]
clear_a(z) # z will not be changed
clear_b(z) # z will be emptied

30voto

Kirk Strauser Points 12087

OK, je vais tenter le coup. Python passe par référence d'objet, ce qui est différent de ce que l'on considère normalement comme "par référence" ou "par valeur". Prenez cet exemple :

def foo(x):
    print x

bar = 'some value'
foo(bar)

Vous créez donc un objet de type chaîne de caractères avec la valeur "une certaine valeur" et vous le "liez" à une variable nommée bar . En C, cela reviendrait à bar étant un pointeur vers une "certaine valeur".

Lorsque vous appelez foo(bar) vous ne passez pas dans bar même. Vous passez dans bar La valeur de la chaîne : un pointeur vers une valeur quelconque. À ce stade, il y a deux "pointeurs" vers le même objet chaîne.

Maintenant, comparez cela à :

def foo(x):
    x = 'another value'
    print x

bar = 'some value'
foo(bar)

C'est là que réside la différence. Dans la ligne :

x = 'another value'

vous ne modifiez pas réellement le contenu du fichier x . En fait, ce n'est même pas possible. Au lieu de cela, vous créez un nouvel objet chaîne de caractères avec la valeur "une autre valeur". Cet opérateur d'affectation ? Il ne dit pas "écrase le truc". x pointe avec la nouvelle valeur". Il dit "mettre à jour x pour pointer vers le nouvel objet à la place". Après cette ligne, il y a deux objets de type chaîne de caractères : "une valeur" (avec l'extension bar en la pointant du doigt) et "une autre valeur" (avec x en le pointant du doigt).

Ce n'est pas maladroit. Lorsque vous comprenez comment il fonctionne, c'est un système magnifiquement élégant et efficace.

28voto

attaboy182 Points 414

J'espère que la description suivante résume bien la situation :

Il y a deux choses à considérer ici : les variables et les objets.

  1. Si vous passez une variable, il s'agit d'un passage par valeur, ce qui signifie que les modifications apportées à la variable dans la fonction sont locales à cette fonction et ne seront donc pas reflétées globalement. Il s'agit plutôt d'un comportement de type 'C'.

Exemple :

def changeval( myvar ):
   myvar = 20; 
   print "values inside the function: ", myvar
   return

myvar = 10;
changeval( myvar );
print "values outside the function: ", myvar

O/P :

values inside the function:  20 
values outside the function:  10
  1. Si vous passez les variables emballées à l'intérieur d'un objet mutable, comme une liste, alors les modifications apportées à l'objet sont reflétées globalement tant que l'objet n'est pas réassigné.

Exemple :

def changelist( mylist ):
   mylist2=['a'];
   mylist.append(mylist2);
   print "values inside the function: ", mylist
   return

mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist

O/P :

values inside the function:  [1, 2, 3, ['a']]
values outside the function:  [1, 2, 3, ['a']]
  1. Considérons maintenant le cas où l'objet est réaffecté. Dans ce cas, l'objet se réfère à un nouvel emplacement mémoire qui est local à la fonction dans laquelle cela se produit et donc non reflété globalement.

Exemple :

def changelist( mylist ):
   mylist=['a'];
   print "values inside the function: ", mylist
   return

mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist

O/P :

values inside the function:  ['a']
values outside the function:  [1, 2, 3]

10voto

Philip Dodson Points 197

Python n'est ni pass-by-value ni pass-by-reference. Il s'agit plutôt de "les références d'objets sont passées par valeur" comme décrit aquí :

  1. Voici pourquoi ce n'est pas du pass-by-value. Parce que

    def append(list):
        list.append(1)
    
    list = [0]
    reassign(list)
    append(list)

renvoie [0,1], ce qui montre qu'une sorte de référence a clairement été transmise en tant que pass-by-value ne permet pas du tout à une fonction de modifier la portée du parent .

Ça ressemble à une passe par référence alors, hein ? Non.

  1. Voici pourquoi ce n'est pas une passe par référence. Parce que

    def reassign(list):
      list = [0, 1]
    
    list = [0]
    reassign(list)
    print list

renvoie [0] montrant que la référence originale a été détruite lorsque la liste a été réaffectée. Le passage par référence aurait retourné [0,1]. .

Pour plus d'informations, consultez aquí :

Si vous voulez que votre fonction ne manipule pas en dehors de la portée, vous devez faire une copie des paramètres d'entrée qui crée un nouvel objet.

from copy import copy

def append(list):
  list2 = copy(list)
  list2.append(1)
  print list2

list = [0]
append(list)
print list

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X