una - paso por valor y paso por referencia python
Pasar un nĂºmero entero por referencia en Python (8)
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 ha pasado por el valor. Entonces, semánticamente, son más o menos lo mismo.
Como mencionas Java en tu pregunta, me gustaría ver cómo logras lo que quieres en Java. Si puede mostrarlo en Java, puedo mostrarle cómo hacerlo exactamente de manera equivalente en Python.
¿Cómo puedo pasar un número 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 pasa por valor, pero tiene que haber un truco fácil. Por ejemplo, en Java podría pasar 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?
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.
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 valores de retorno múltiples, 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
No funciona del todo así en Python. Python pasa referencias a objetos. Dentro de tu función tienes un objeto: puedes mutar ese objeto (si es posible). Sin embargo, los enteros son inmutables . Una solución consiste en pasar el entero en un contenedor que puede mutarse:
def change(x):
x[0] = 3
x = [1]
change(x)
print x
Esto es feo / torpe en el mejor de los casos, pero no vas a mejorar en Python. La razón es porque en Python, la asignación ( =
) toma cualquier objeto que sea el resultado del lado derecho y lo vincula con lo que está en el lado izquierdo * (o lo pasa a la función apropiada).
Entendiendo esto, podemos ver por qué no hay forma de cambiar el valor de un objeto inmutable dentro de una función: no puedes cambiar ninguno de sus atributos porque es inmutable, y no puedes simplemente asignarle a la "variable" un nuevo valor porque en realidad está creando un nuevo objeto (que es distinto del anterior) y dándole 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, 3
se pasa a x.__setitem__
.
Realmente, la mejor práctica es dar un paso atrás y preguntar 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 ataque rápido, la forma más rápida es pasar una list
contenga el número entero, y pegar un [0]
en cada uso de la misma, como lo demuestra la respuesta de mgilson.
Si necesita hacerlo para algo más significativo, escriba una class
que tenga un atributo int
como un atributo, para que pueda simplemente configurarlo. Por supuesto, esto te obliga a encontrar 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 la list
.
De manera más general, si estás intentando portar algún modismo de Java directamente a Python, lo estás haciendo mal. Incluso cuando hay algo que se corresponde directamente (como con static
/ @staticmethod
), todavía no desea usarlo en la mayoría de los programas de Python simplemente porque lo usaría en Java.
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):
v.i += 1
x = type('''', (), {})()
x.i = 7
inc_i(x)
print(x.i)
Una matriz numpy de un solo elemento es mutable y, sin embargo, para la mayoría de los propósitos, se puede evaluar como si fuera una variable numérica python. Por lo tanto, es un contenedor de números de referencia por referencia más conveniente que una lista de elementos individuales.
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
class PassByReference:
def Change(self, var):
self.a = var
print(self.a)
s=PassByReference()
s.Change(5)