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 forma de hacerlo es usando la palabra reservada global (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 sin cambios
En este ejemplo, la variable n nunca se cambia
Ejemplo 2:
n = 0
def foo():
global n
n = n * n
return n
En este ejemplo se cambia la variable n
¿Hay alguna forma en Python de 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 solo valor, mientras que un procedimiento devuelve más de un valor. Me enseñaron que una función tiene una declaración de retorno y un procedimiento no, durante los años 80. ¿Por qué esto ahora es incorrecto?
n
cambiaría, está utilizando una nueva variablesquare
para almacenar el resultado de su cálculo.Respuestas:
No puede cambiar un objeto inmutable, como
str
otuple
, dentro de una función en Python, pero puede hacer cosas como:def foo(y): y[0] = y[0]**2 x = [5] foo(x) print x[0] # prints 25
Sin embargo, esa es una forma extraña de hacerlo, a menos que siempre necesite cuadrar ciertos elementos en una matriz.
Tenga en cuenta que en Python, también puede devolver más de un valor, lo que hace que algunos de los casos de uso para pasar por referencia sean menos importantes:
def foo(x, y): return x**2, y**2 a = 2 b = 3 a, b = foo(a, b) # a == 4; b == 9
Cuando devuelve valores como ese, se devuelven como una tupla que a su vez se desempaqueta.
editar: Otra forma de pensar en esto es que, si bien no puede pasar variables explícitamente por referencia en Python, puede modificar las propiedades de los objetos que se pasaron. En mi ejemplo (y otros) puede modificar miembros de la lista que se pasó en. Sin embargo, no podrá reasignar la variable pasada en por completo. Por ejemplo, observe que los siguientes dos fragmentos de código parecen que podrían 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
fuente
clear_a
recibe una referenciaz
y almacena esa referencia enx
. Luego cambia inmediatamentex
para hacer referencia a una matriz diferente. Laz
matriz original se olvida en el alcance declear_a
, pero en realidad no se cambia. Continúa sin cambios al volver al ámbito global. Contraste eso con elclear_b
que toma una referenciaz
y luego opera directamente sobre él, sin nunca crear una nueva matriz o señalarx
algo diferente.y = x
,y: y.pop()
y luego llaméclear_b(z)
, z aún así nos vació ... Así que necesitamos algo comoy = list(x)
para crear una copia de x (lista (x) se explica aquí )run_thread = [True] t= threading.Thread(target=module2.some_method, \ args=(11,1,run_thread)) --do something - and when you want to sop run_thread[0] =False
Básicamente, existen tres tipos de 'llamadas a funciones':
Python es un lenguaje de programación PASAR POR OBJETO-REFERENCIA.
En primer lugar, es importante comprender que una variable y el valor de la variable (el objeto) son dos cosas distintas. La variable 'apunta' al 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 enx
sí misma 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.PASAR POR REFERENCIA DE OBJETO (Caso en Python):
Aquí, "Las referencias a 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]
crea una variablex
(caja) que apunta hacia el objeto[0]
.En la función que se llama,
li
se crea una nueva caja . El contenido deli
es el MISMO que el contenido de la cajax
. Ambas cajas contienen el mismo objeto. Es decir, ambas variables apuntan al mismo objeto en la memoria. Por tanto, cualquier cambio en el objeto apuntado porli
también será reflejado por el objeto apuntado porx
.En conclusión, el resultado del programa anterior será:
[0, 1]
Nota:
Si la variable
li
se reasigna en la función,li
apuntará a un objeto separado en la memoria.x
sin embargo, seguirá apuntando al mismo objeto en la memoria al que apuntaba anteriormente.Ejemplo:
def append_one(li): li = [0, 1] x = [0] append_one(x) print x
La salida del programa será:
[0]
PASO POR REFERENCIA:
El cuadro de la función que llama se pasa a la función llamada. Implícitamente, el contenido del cuadro (el valor de la variable) se pasa 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 llamada.
PASO POR VALOR:
Se crea un nuevo cuadro en la función llamada y se almacenan copias del contenido del cuadro de la función que llama en los nuevos cuadros.
Espero que esto ayude.
fuente
Bien, intentaré esto. Python pasa por referencia de objeto, que es diferente de lo que normalmente pensarías como "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 lo "vincula" a una variable nombrada
bar
. En C, eso sería similar abar
ser un puntero a 'algún valor'.Cuando llamas
foo(bar)
, no estás pasando porbar
sí mismo. Estás pasandobar
un valor: un puntero a "algún valor". En ese momento, hay dos "punteros" al 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á 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 está diciendo "sobrescribir la cosax
que apunta con el nuevo valor". Dice "actualizarx
para apuntar al nuevo objeto en su lugar". Después de esa línea, hay dos objetos de cadena: 'algún valor' (bar
apuntándolo) y 'otro valor' (x
apuntándolo).Esto no es torpe. Cuando comprende cómo funciona, es un sistema eficiente y bellamente elegante.
fuente
str
entradas, lostuple
sy otros objetos son inmutables . Si pasa un objeto mutable, como alist
, puede cambiarlo dentro de la función, sin la necesidad de devolverlo, porque todos los parámetros de la función son punteros a los mismos objetos que pasó.Espero que la siguiente descripción lo resuma bien:
Hay dos cosas a considerar aquí: variables y objetos.
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
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']]
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]
fuente
Python no es paso por valor ni paso por referencia. Es más "las referencias de objeto se pasan por valor" como se describe aquí :
He aquí por qué no se transmite por valor. Porque
def append(list): list.append(1) list = [0] reassign(list) append(list)
devuelve [0,1] que muestra que se pasó claramente algún tipo de referencia ya que el valor de paso por valor no permite que una función altere el alcance principal en absoluto .
Entonces parece pasar por referencia, ¿eh? No
He aquí por qué no se pasa por referencia. Porque
def reassign(list): list = [0, 1] list = [0] reassign(list) print list
devuelve [0] que muestra que la referencia original se destruyó cuando se reasignó la lista. pass-by-reference habría devuelto [0,1] .
Para obtener más información, consulte aquí :
Si desea que su función no manipule fuera del alcance, necesita 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
fuente
Técnicamente, Python no pasa argumentos por valor: todos por referencia. Pero ... dado que Python tiene dos tipos de objetos: inmutables y mutables, esto es lo que sucede:
Los argumentos inmutables se pasan efectivamente por valor : cadena, entero, tupla son todos tipos de objetos inmutables. Aunque técnicamente se "pasan por referencia" (como todos los parámetros), dado que no puede cambiarlos en el lugar dentro de la función, se ve / se comporta como si se pasara por valor.
Los argumentos mutables se pasan efectivamente por referencia : las listas o diccionarios se pasan por sus punteros. Cualquier cambio en el lugar dentro de la función como (agregar o eliminar) afectará al objeto original.
Así es como está diseñado Python: no hay copias y todas se pasan por referencia. Puede pasar explícitamente una copia.
def sort(array): # do sort return array data = [1, 2, 3] sort(data[:]) # here you passed a copy
El último punto que me gustaría mencionar es que una función tiene su propio alcance.
def do_any_stuff_to_these_objects(a, b): a = a * 2 del b['last_name'] number = 1 # immutable hashmap = {'first_name' : 'john', 'last_name': 'legend'} # mutable do_any_stuff_to_these_objects(number, hashmap) print(number) # 1 , oh it should be 2 ! no a is changed inisde the function scope print(hashmap) # {'first_name': 'john'}
fuente
Así que este es un punto un poco sutil, porque mientras 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 mal estilo, y si realmente desea mutar sus valores, debe escribir una clase y llamar a métodos dentro de esa clase, como sugiere MPX.
fuente
y = [a for a in x]; y[0] = 3; return y
x = foo(x)
.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])
cuál 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, sino que implica mutar el parámetro original de alguna manera manualmente, por ejemplo, cambiando el parámetro original a una lista: o copiándolo en otra lista en lugar de simplemente decir: "use este parámetro como un valor" o "use este como una referencia". ¿Podría la respuesta simple ser que no hay una palabra reservada para esto, pero estas son excelentes soluciones?
fuente
Considere que la variable es un cuadro y el valor al que apunta es la "cosa" dentro del cuadro:
1. Pasar por referencia: la función comparte la misma caja y, por tanto, la cosa que está dentro también.
2. Pasar por valor: la función crea una nueva caja, una réplica de la anterior, incluyendo una copia de lo que esté dentro. P.ej. Java : las funciones crean una copia de la caja y lo que está dentro de ella, que puede ser: una primitiva / una referencia a un objeto. (tenga en cuenta que la referencia copiada en el nuevo cuadro y el original todavía apuntan al mismo objeto, aquí la referencia ES lo que está dentro del cuadro, no el objeto al que apunta)
3. Pasar por referencia de objeto : la función crea una caja, pero encierra lo mismo que la caja inicial. Entonces en Python :
a) si lo que está dentro de dicha caja es mutable , los cambios realizados se reflejarán en la caja original (por ejemplo, listas)
b) si la cosa es inmutable (como cadenas de Python y tipos numéricos), entonces el cuadro dentro de la función contendrá lo mismo HASTA que intente cambiar su valor. Una vez cambiado, lo que está en el cuadro de la función es algo totalmente nuevo en comparación con el original. Por lo tanto, id () para esa caja ahora dará la identidad de lo nuevo que encierra .
fuente
class demoClass: x = 4 y = 3 foo1 = demoClass() foo1.x = 2 foo2 = demoClass() foo2.y = 5 def mySquare(myObj): myObj.x = myObj.x**2 myObj.y = myObj.y**2 print('foo1.x =', foo1.x) print('foo1.y =', foo1.y) print('foo2.x =', foo2.x) print('foo2.y =', foo2.y) mySquare(foo1) mySquare(foo2) print('After square:') print('foo1.x =', foo1.x) print('foo1.y =', foo1.y) print('foo2.x =', foo2.x) print('foo2.y =', foo2.y)
fuente
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 en realidad hace este paso 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 pasa una cadena, esta transmisión se realiza por valor, por lo que se crea un nuevo objeto de cadena y cuando la función termina, se destruye. Entonces, todo tiene que ver con objetos mutables e inmutables.
fuente
Python ya llama por ref ..
tomemos un 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
fuente
def foo(var): print(id(var)) var = 1234 print(id(var)) x = 123 print(id(x)) # I think the id() give the ref... foo(x) print(id(x))