7. Pasaje por Referencia

7.1. Más información

Repasemos unos conceptos.

En Python todo es un objeto.


Cada Objeto se almacena en una Dirección que es única para ese objeto ( cada objeto tiene su "casa")

Para facilitar y no tener que recordar una dirección se usa un nombre ( ej: "La_Facultad" ) que para nosotros sería el nombre de la variable, pero en realidad es una referencia a un objeto ( 'Juan Manuel de Rosas 325")

Una declaración típica:

< identifier > = < expression>

Ver que hay un igual este igual NO es simplemente una asignación, implica la creación referencia a un Objeto.

x = 1 # declaro el objeto 1, y la referencia x, señala a objeto 1.

# una o varias sentencias.

x = x + 2 # no es un suma algebraica solamente aunque parece, es una sentencia de asignación => crea una referencia a un nuevo objeto

Esta asignación se lee de derecha a izquiera de la siguiente manera:

La referencia a x nueva, se actualiza para apuntar a una nuevo valor que resulta del valor apuntado anteriormente mas dos.
La dirección nueva de x y la anterior NO son la misma.

El espacio de la x anterior es reclamado por un "Recolector de Basura" que recupera las direcciones sin uso para usar mas tarde.

Veamos como sería de manera Gráfica:

 Figura 1

Es importante entender  que el igual, no es una simple asignación, si no la creación de un Nuevo objeto. 

Si hay un igual => es un nuevo objeto!!

Veamos otro ejemplo:

 Figura 2

La salida de esto sería:

  Figura 3

Con esto en mente es mas fácil entender los que sigue.

Pasaje por valor

Si usamos un parámetro pasado por valor, se creará una copia local de la variable, lo que implica que cualquier modificación sobre la misma no tendrá efecto sobre la original.
Veamos este caso:

Aquí se prestaría a confusión, ya que la x definida en la función deja de existir en la línea 2, por que hay un igual.
Es decir se crea un objeto NUEVO, solo que se toma el valor de x y se crea un objeto nuevo con un valor duplicado.
ese valor duplicado se muestra en main en línea 6 que es lo que retorna la función duplicar.
En la línea 7 se muestra el valor ingresado.. se puede ver que no cambió.


Se podría dar otro nombre a la variable x dentro de la función y NO CAMBIARÍA NADA.
Esto se conoce como pasaje por valor.
Se deja al alumno en análisis del siguiente código:

¿Que saldría tendría y por que?

Pasaje por referencia

En Python al pasar una variable como argumento de una función estas se pasan por referencia o por valor.

Con una variable pasada como referencia, se actuará directamente sobre la variable pasada, por lo que las modificaciones afectarán a la variable original.

Vimos en la sección anterior el pasaje por Valor.

  Figura 4

En este scritp el valor de z no se duplica, por mas que se lo duplica en la función, esto no se refleja entre las líneas 11 a 13.

Por otro lado se aconseja NO  declarar las Variables como Globales, recordemos que así si se podían cambiar los valores.

Pero va a ser necesario que la función pueda realizar cambios.

 Así que ¿cual es la solución para que una función pueda alterar un valor y que el mismo sea permanente sin que la variable sea Global?

Respuesta : Pasaje por Referencia!!

En el paso por valor, que vimos en la sección anterior , lo que se pasa como argumento es el valor que contenía la variable, una copia no el valor original (parámetro), por eso las modificaciones hechas en las NO se reflejan fuera de la función, por que es una COPIA.

Si se relaciona con el concepto de Objetos vemos que al poner el = dentro de la función creo OTRO OBJETO. En la figura 4, dentro de la función en la línea 9 hay un igual..

esto hace que se cree un NUEVO OBJETO, pero se referencia a el valor z por 2.. y esta z dentro de la función no es lo mismo que la z fuera de la función, son objetos distintos que tienen igual nombre.. podríamos pensar que son dos alumnos que se llaman Juan y está en distintas aulas .. pero no son la misma persona.

En el paso por  referencia lo que se pasa como argumento es la referencia al objeto o nombre del objeto PERO NO SE PUEDE USAR EL = , POR QUE SE CREA OTRO OBJETO. 

Por eso debo pasar datos que pueda modificar sin usar el =.

Veamos con un ejemplo:

 Figura 5

  • Vemos que el valor de x0 NO se altera, dentro de la función vale 4 y fuera de la función SIEMPRE vale 1. Dentro de la función línea 23 hay un igual => Creo un nuevo objeto!
  • Vemos que el valor de y0, que se llama dentro de la función y1, SI CAMBIA, de hecho se agrega un valor 23 y se mantiene al finalizar la función. Dentro de la función línea 24 NO hay un igual => NO creo otro objeto, es el MISMO.
  • y0 es una LISTA,  x0 es un entero
  • x0 no se puede cambiar, para cambiar uso el = y esto crea otro objeto
  • y0 SI se puede cambiar, no uso el = , si uso un método append.

¿Por que uno  si y0  y otro no?

La respuesta es que las variables de tipo números enteros ( nombre de referencia de los objetos) son inmutables, no ha manera de hacer nada con ellos sin usar el =.

Es decir, una vez creados, su valor no puede ser modificado y si quiero modificar tengo que usar el =

¿Pero cuando hago a = 1 y luego a = 2, si se puede cambiar?

Respuesta:  Claro, pero desde la perspectiva del lenguaje, no estás cambiando el valor de a de 1 a 2 sino quitando la referencia a 1 y poniéndosela a 2. El igual hace eso.

En términos más simples, no «cambias» el valor de un objeto sino que le asignas una nueva referencia.

Objetos Python según su mutabilidad:

MutablesInmutables
dict
list
 bool
 bytes
 complex
 decimal
 int
 float
 str/unicode
 tuple
 range

Podemos ver aquí como Listas y Diccionarios se vuelven mas importantes.

Tradicionalmente:

    Los tipos simples se pasan por valor: Enteros, flotantes, cadenas, lógicos, etc.
    Los tipos compuestos se pasan por referencia: Listas, diccionarios.

En este punto parecería que solo pasando Objetos Mutables ( ej. Lista como y0 )  podemos cambiar un valor.

Bueno no es necesariamente hay una alternativa, se puede devolverlos modificados y reasignarlos, veamos las dos alternativas de modificar valores.

1) Pasando un objeto alterable ( Lista, Diccionario)

2) Pasando un objeto in-alterable pero usando en return para regresar una copia del nuevo objeto

3) Usando una variable Global ( NO USAR ESTE!!)

 Figura 2.

Pasar los argumentos por referencia es pasar tipos de dato mutables y cambiarlos sin usar el igual., y los inmutables por valor.

Vemos un caso en el que uso una lista, pero dentro de la función uso un =, por lo tanto se crea Otro objeto veamos un ejemplo:

 Figura 3

Cuando se pasan por Referencia SI se pueden cambiar si no uso el  , cuando se pasan por valor NO se pueden cambiar!