Pasando un entero por referencia en Python

¿Cómo puedo pasar un entero por referencia en Python?

Quiero modificar el valor de una variable que 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 puede pasar los tipos de referencia de Integer , Long , etc.

  1. ¿Cómo puedo pasar un entero a una función por referencia?
  2. ¿Cuáles son las mejores prácticas?

No funciona del mismo modo en Python. Python pasa referencias a objetos. Dentro de tu función tienes un objeto: eres libre de mutar ese objeto (si es posible). Sin embargo, los enteros son inmutables . Una solución es pasar el entero en un contenedor que puede ser mutado:

 def change(x): x[0] = 3 x = [1] change(x) print x 

Esto es feo / torpe en el mejor de los casos, pero no lo harás mejor en Python. La razón es que 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).

Entendiendo esto, podemos ver por qué no hay manera 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 valor porque entonces en realidad estás creando un nuevo objeto (que es distinto del anterior) y le das el nombre que tenía el objeto antiguo en el espacio de nombres local.

Usualmente, 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, 3 realmente se pasa a x.__setitem__ .

La mayoría de los casos en los que necesitaría pasar por referencia es cuando necesita devolver más de un valor a la persona que llama. Una “mejor práctica” es usar múltiples valores de retorno, que es mucho más fácil de hacer en Python que en lenguajes como Java.

Aquí hay un ejemplo simple:

 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 

Realmente, la mejor práctica es dar un paso atrás y preguntar si realmente necesita hacer esto. ¿Por qué desea modificar el valor de una variable que está pasando a la función?

Si necesita hacerlo para un pirateo rápido, la forma más rápida es pasar una list contenga el número entero y pegar un [0] en cada uso, como lo demuestra la respuesta de mgilson.

Si necesita hacerlo por algo más significativo, escriba una class que tenga un int como un atributo, de modo que pueda configurarlo. Por supuesto, esto lo obliga a encontrar un buen nombre para la clase y para el atributo: si no puede pensar en nada, vuelva atrás y lea la oración varias veces, y luego use la list .

En términos más generales, si estás intentando portar algún lenguaje Java directamente a Python, lo estás haciendo mal. Incluso cuando hay algo directamente correspondiente (como con static / @staticmethod ), todavía no quieres usarlo en la mayoría de los progtwigs de Python solo porque lo usarías en Java.

 class PassByReference: def Change(self, var): self.a = var print(self.a) s=PassByReference() s.Change(5) 

En Python, cada valor es una referencia (un puntero a un objeto), al igual que los no primitivos en Java. Además, al igual que Java, Python solo tiene pase por valor. Entonces, semánticamente, son más o menos iguales.

Como menciona Java en su pregunta, me gustaría ver cómo logra lo que desea en Java. Si puedes mostrarlo en Java, puedo mostrarte cómo hacerlo exactamente de manera equivalente en Python.

Una matriz de un solo elemento numpy es mutable y, sin embargo, para la mayoría de los propósitos, puede evaluarse como si fuera una variable de python numérica. Por lo tanto, es un contenedor de número de 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 

No exactamente pasar un valor directamente, pero usarlo como si se hubiera pasado.

 x = 7 def my_method(): nonlocal x x += 1 my_method() print(x) # 8 

Advertencias:

  • nonlocal fue introducido en Python 3.
  • Si el ámbito adjunto es el global, use global lugar de nonlocal .

Tal vez un poco más de auto-documentación que el truco de la lista de longitud 1 es el viejo truco de tipo vacío:

 def inc_i(v): vi += 1 x = type('', (), {})() xi = 7 inc_i(x) print(xi) 

En Python, todo se pasa por valor, pero si desea modificar algún estado, puede cambiar el valor de un número entero dentro de una lista u objeto que se pasa a un método.