¿Cómo puedo pasar un número entero por referencia en Python?
Quiero modificar el valor de una variable que le estoy pasando a la función. He leído que todo en Python se pasa por valor, pero tiene que haber un truco fácil. Por ejemplo, en Java que podría pasar a los tipos de referencia de Integer
, Long
, etc.
- ¿Cómo puedo pasar un número entero a una función por referencia?
- ¿Cuáles son las mejores prácticas?
python
function
pass-by-reference
pass-by-value
CodeKingPlusPlus
fuente
fuente
Respuestas:
No funciona de esa manera en Python. Python pasa referencias a objetos. Dentro de su función tiene un objeto: puede mutar ese objeto (si es posible). Sin embargo, los números enteros son inmutables . Una solución es pasar el número entero en un contenedor que se puede mutar:
def change(x): x[0] = 3 x = [1] change(x) print x
Esto es feo / torpe en el mejor de los casos, pero no le irá mejor en Python. La razón es porque en Python, la asignación (
=
) toma cualquier objeto que sea el resultado del lado derecho y lo une a lo que esté en el lado izquierdo * (o lo pasa a la función apropiada).Al comprender esto, podemos ver por qué no hay forma de cambiar el valor de un objeto inmutable dentro de una función: no puede cambiar ninguno de sus atributos porque es inmutable y no puede simplemente asignar a la "variable" una nueva value porque entonces en realidad está creando un nuevo objeto (que es distinto del anterior) y le está dando el nombre que tenía el objeto anterior en el espacio de nombres local.
Por lo general, la solución es simplemente devolver el objeto que desea:
def multiply_by_2(x): return 2*x x = 1 x = multiply_by_2(x)
* En el primer caso de ejemplo anterior, en
3
realidad se pasa ax.__setitem__
.fuente
C
. (No es necesario desreferenciarlos, por ejemplo). En mi modelo mental, es más fácil pensar en las cosas como "Nombres" y "Objetos". La asignación vincula un "Nombre" (s) a la izquierda a un "Objeto" (s) a la derecha. Cuando llamas a una función, pasas el "Objeto" (enlazándolo efectivamente a un nuevo nombre local dentro de la función)..
operador simplemente elimina la referencia del lado izquierdo. Los operadores pueden ser diferentes en diferentes idiomas.La mayoría de los casos en los que necesitaría pasar por referencia son aquellos en los que debe devolver más de un valor a la persona que llama. Una "mejor práctica" es usar múltiples valores de retorno, lo cual es mucho más fácil de hacer en Python que en lenguajes como Java.
He aquí un ejemplo sencillo:
def RectToPolar(x, y): r = (x ** 2 + y ** 2) ** 0.5 theta = math.atan2(y, x) return r, theta # return 2 things at once r, theta = RectToPolar(3, 4) # assign 2 things at once
fuente
No exactamente pasando un valor directamente, sino usándolo como si fuera pasado.
x = 7 def my_method(): nonlocal x x += 1 my_method() print(x) # 8
Advertencias:
nonlocal
fue introducido en Python 3global
lugar denonlocal
.fuente
Realmente, la mejor práctica es dar un paso atrás y preguntarse si realmente necesita hacer esto. ¿Por qué quiere modificar el valor de una variable que está pasando a la función?
Si necesita hacerlo para un truco rápido, la forma más rápida es pasar un
list
número entero y quedarse con[0]
cada uso, como lo demuestra la respuesta de mgilson.Si necesita hacerlo para algo más significativo, escriba un
class
que tengaint
como atributo, para que pueda configurarlo. Por supuesto, esto te obliga a pensar en un buen nombre para la clase y para el atributo; si no puedes pensar en nada, vuelve a leer la oración varias veces y luego usa ellist
.De manera más general, si está intentando portar algún modismo de Java directamente a Python, lo está haciendo mal. Incluso cuando hay algo directamente correspondiente (como con
static
/@staticmethod
), todavía no desea usarlo en la mayoría de los programas de Python solo porque lo usaría en Java.fuente
En Python, cada valor es una referencia (un puntero a un objeto), al igual que los no primitivos en Java. Además, como Java, Python solo tiene paso por valor. Entonces, semánticamente, son más o menos lo mismo.
Dado que menciona Java en su pregunta, me gustaría ver cómo logra lo que desea en Java. Si puede mostrarlo en Java, puedo mostrarle cómo hacerlo exactamente de manera equivalente en Python.
fuente
Una matriz de un solo elemento numpy es mutable y, sin embargo, para la mayoría de los propósitos, se puede evaluar como si fuera una variable numérica de Python. Por lo tanto, es un contenedor de números por referencia más conveniente que una lista de un solo elemento.
import numpy as np def triple_var_by_ref(x): x[0]=x[0]*3 a=np.array([2]) triple_var_by_ref(a) print(a+1)
salida:
3
fuente
class PassByReference: def Change(self, var): self.a = var print(self.a) s=PassByReference() s.Change(5)
fuente
Tal vez no sea una forma pitónica, pero puedes hacer esto
import ctypes def incr(a): a += 1 x = ctypes.c_int(1) # create c-var incr(ctypes.ctypes.byref(x)) # passing by ref
fuente
Quizás un poco más autodocumentado que el truco de la lista de longitud 1 es el viejo truco de tipo vacío:
def inc_i(v): v.i += 1 x = type('', (), {})() x.i = 7 inc_i(x) print(x.i)
fuente
En Python, todo se pasa por valor, pero si desea modificar algún estado, puede cambiar el valor de un entero dentro de una lista u objeto que se pasa a un método.
fuente
everything is passed by value
no es realmente cierto.arguments are passed using call by value (where the value is always an object reference, not the value of the object)
La respuesta correcta es usar una clase y poner el valor dentro de la clase, esto le permite pasar por referencia exactamente como lo desee.
class Thing: def __init__(self,a): self.a = a def dosomething(ref) ref.a += 1 t = Thing(3) dosomething(t) print("T is now",t.a)
fuente