propias - Las funciones de Python llaman por referencia
llamar funciones dentro de funciones python (9)
Así que este es un punto un poco sutil, porque mientras que Python solo pasa variables por valor, cada variable en Python es una referencia. Si desea poder cambiar sus valores con una llamada de función, lo que necesita es un objeto mutable. Por ejemplo:
l = [0]
def set_3(x):
x[0] = 3
set_3(l)
print(l[0])
En el código anterior, la función modifica el contenido de un objeto List (que es mutable), por lo que la salida es 3 en lugar de 0.
Escribo esta respuesta solo para ilustrar lo que significa ''por valor'' en Python. El código anterior es de estilo incorrecto, y si realmente quieres mutar tus valores, debes escribir una clase y llamar a los métodos dentro de esa clase, como sugiere MPX.
En algunos idiomas, puede pasar un parámetro por referencia o valor utilizando una palabra reservada especial como ref o val . Cuando pasa un parámetro a una función de Python, nunca altera el valor del parámetro al salir de la función. La única manera de hacerlo es mediante el uso de la palabra global reservada (o, como la entiendo actualmente).
Ejemplo 1:
k = 2
def foo (n):
n = n * n #clarity regarding comment below
square = n
return square
j = foo(k)
print j
print k
mostraría
>>4
>>2
mostrando k para ser sin cambios
En este ejemplo, la variable n nunca cambia
Ejemplo 2:
n = 0
def foo():
global n
n = n * n
return n
En este ejemplo, la variable n se cambia
¿Hay alguna forma en Python para llamar a una función y decirle a Python que el parámetro es un valor o un parámetro de referencia en lugar de usar global?
En segundo lugar, en los exámenes de Cambridge de nivel A ahora dicen que una función devuelve un único valor mientras que un procedimiento devuelve más de un valor. Me enseñaron que una función tiene una declaración de devolución y el procedimiento no, durante los años 80. ¿Por qué esto ahora es incorrecto?
De acuerdo, daré una estocada. Python pasa por referencia de objeto, que es diferente de lo que normalmente consideraría "por referencia" o "por valor". Toma este ejemplo:
def foo(x):
print x
bar = ''some value''
foo(bar)
Así que está creando un objeto de cadena con el valor ''algún valor'' y "vinculándolo" a una variable llamada bar
. En C, eso sería similar a que bar
sea un puntero a ''algún valor''.
Cuando llamas a foo(bar)
, no pasas en la bar
. Estás pasando el valor de la bar
: un puntero a ''algún valor''. En ese punto, hay dos "punteros" para el mismo objeto de cadena.
Ahora compare eso con:
def foo(x):
x = ''another value''
print x
bar = ''some value''
foo(bar)
Aquí es donde radica la diferencia. En la linea:
x = ''another value''
en realidad no estás alterando el contenido de x
. De hecho, eso ni siquiera es posible. En su lugar, está creando un nuevo objeto de cadena con el valor ''otro valor''. Ese operador de asignación? No es decir "sobrescribir lo que x
está señalando con el nuevo valor". Se está diciendo "actualizar x
para apuntar al nuevo objeto en su lugar". Después de esa línea, hay dos objetos de cadena: ''algún valor'' (con bar
apuntando a él) y ''otro valor'' (con x
apuntando a él).
Esto no es torpe Cuando entiendes cómo funciona, es un sistema maravillosamente elegante y eficiente.
En Python, el paso por referencia o por valor tiene que ver con cuáles son los objetos reales que está pasando. Entonces, si está pasando una lista por ejemplo, entonces realmente hace que pase por referencia, ya que la lista es un objeto mutable. Por lo tanto, está pasando un puntero a la función y puede modificar el objeto (lista) en el cuerpo de la función.
Cuando está pasando una cadena, este paso se realiza por valor, por lo que se está creando un nuevo objeto de cadena y cuando la función termina, se destruye. Entonces todo tiene que ver con objetos mutables e inmutables.
Espero que la siguiente descripción lo resuma bien:
Aquí hay dos cosas a considerar: variables y objetos.
- Si está pasando una variable, se pasa por valor, lo que significa que los cambios realizados en la variable dentro de la función son locales para esa función y, por lo tanto, no se reflejarán globalmente. Esto es más un comportamiento tipo ''C''.
Ejemplo:
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
- Si está pasando las variables empaquetadas dentro de un objeto mutable, como una lista, los cambios realizados en el objeto se reflejan globalmente siempre que el objeto no se vuelva a asignar.
Ejemplo:
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'']]
- Ahora considere el caso donde el objeto se reasigna. En este caso, el objeto se refiere a una nueva ubicación de memoria que es local para la función en la que esto sucede y, por lo tanto, no se refleja globalmente.
Ejemplo:
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]
Hay esencialmente tres tipos de ''llamadas a funciones'':
- Pase por valor
- Pase por referencia
- Pase por referencia de objeto
Python es un lenguaje de programación PASS-BY-OBJECT-REFERENCE.
En primer lugar, es importante comprender que una variable y el valor de la variable (el objeto) son dos cosas separadas. La variable ''apunta a'' el objeto. La variable no es el objeto. De nuevo:
LA VARIABLE NO ES EL OBJETO
Ejemplo: en la siguiente línea de código:
>>> x = []
[] es la lista vacía, x es una variable que apunta a la lista vacía, pero x en sí no es la lista vacía
Considere la variable (x, en el caso anterior) como un cuadro, y ''el valor'' de la variable ([]) como el objeto dentro del cuadro.
PASS BY OBJECT REFERENCE (Caso en python):
Aquí, "Las referencias de objetos se pasan por valor".
def append_one(li):
li.append(1)
x = [0]
append_one(x)
print x
Aquí, la declaración x = [0] hace una variable x (caja) que apunta hacia el objeto [0]
En la función a la que se llama, se crea un nuevo cuadro li. El contenido de li es el MISMO que el contenido del cuadro x. Ambas cajas contienen el mismo objeto. Es decir, ambas variables apuntan al mismo objeto en la memoria. Por lo tanto, cualquier cambio en el objeto apuntado por li también se verá reflejado por el objeto apuntado por x.
En conclusión, el resultado del programa anterior será:
[0, 1]
Nota:
Si la variable li se reasigna en la función, entonces li apuntará a un objeto separado en la memoria. x sin embargo, continuará apuntando al mismo objeto en la memoria a la que apuntaba anteriormente.
Ejemplo:
def append_one(li):
li = [0, 1]
x = [0]
append_one(x)
print x
El resultado del programa será:
[0]
PASAR POR REFERENCIA:
El cuadro de la función de llamada se transfiere a la función llamada. Implícitamente, el contenido del cuadro (el valor de la variable) se transfiere a la función llamada. Por lo tanto, cualquier cambio en el contenido del cuadro en la función llamada se reflejará en la función de llamada.
PASAR POR VALOR:
Se crea un nuevo cuadro en la función llamada, y las copias del contenido del cuadro de la función de llamada se almacenan en los nuevos cuadros.
Espero que esto ayude.
La respuesta dada es
def set_4(x):
y = []
for i in x:
y.append(i)
y[0] = 4
return y
y
l = [0]
def set_3(x):
x[0] = 3
set_3(l)
print(l[0])
que es la mejor respuesta en la medida en que hace lo que dice en la pregunta. Sin embargo, parece una forma muy torpe en comparación con VB o Pascal. ¿Es el mejor método que tenemos?
No solo es torpe, implica mutar el parámetro original de alguna manera manualmente, por ejemplo cambiando el parámetro original a una lista: o copiándolo a otra lista en lugar de solo decir: "use este parámetro como un valor" o "use este" como una referencia". ¿Podría ser la respuesta simple que no hay palabras reservadas para esto, pero estas son excelentes soluciones?
No puede pasar una primitiva simple por referencia en Python, pero puede hacer cosas como las siguientes:
def foo(y):
y[0] = y[0]**2
x = [5]
foo(x)
print x[0] # prints 25
Sin embargo, esa es una manera extraña de hacerlo. Tenga en cuenta que en Python, también puede devolver más de un valor, por lo que algunos de los casos de uso para pasar por referencia son menos importantes:
def foo(x, y):
return x**2, y**2
a = 1
b = 2
a, b = foo(a, b) # a == 2; b == 4
Cuando devuelve valores como ese, se devuelven como Tuple, que a su vez se desempaqueta.
editar: Otra forma de pensar sobre esto es que, aunque no se pueden pasar explícitamente variables por referencia en Python, puede modificar las propiedades de los objetos que se pasaron. En mi ejemplo (y otros) puede modificar los miembros de la lista eso fue aprobado. Sin embargo, no podrías reasignar por completo la variable pasada. Por ejemplo, vea los siguientes dos códigos de código que parecen hacer algo similar, pero terminan con resultados diferentes:
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
Python no es ni pass-by-value ni pass-by-reference. Se trata más de "referencias de objeto pasadas por valor" como se describe aquí: http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/ .
He aquí por qué no se trata de pasar por valor. Porque
def append (list):
list.append (1)list = [0]
reasignar (lista)
anexar (lista)
devuelve [0,1] que muestra que algún tipo de referencia se aprobó claramente, ya que pass-by-value no permite que una función altere el alcance padre en absoluto .
Parece una referencia pasada, ¿hu? Nop.
He aquí por qué no es de pasada por referencia. Porque
def reasignar (lista):
list = [0, 1]list = [0]
reasignar (lista)
lista de impresión
devuelve [0] que muestra que la referencia original se destruyó cuando se reasignó la lista. pass-by-reference habría regresado [0,1] .
Para obtener más información, consulte aquí: effbot.org/zone/call-by-object.htm
Si desea que su función no manipule el ámbito externo, debe hacer una copia de los parámetros de entrada que crea un nuevo objeto.
from copy import copy
def append(list):
list2 = copy(list)
list2.append(1)
print list2
list = [0]
append(list)
print list
Python ya llama por ref ..
Tomemos el ejemplo:
def foo(var):
print(hex(id(var)))
x = 1 # any value
print(hex(id(x))) # I think the id() give the ref...
foo(x)
Salida
0x50d43700 #with you might give another hex number deppend on your memory
0x50d43700