Argumentos Mutables en Funciones

Python tiene una variedad de tipos de datos, algunos de los cuales pueden modificarse después de su creación y otros no. Cuando hablamos de tipos que pueden modificarse, nos referimos a ellos como tipos "mutables". En contraste, aquellos que no pueden cambiarse se denominan tipos "inmutables".

Tipos Mutables

Los tipos mutables más comunes son las list, dict y set. Aquí hay un ejemplo de una lista:
fruits = ['apple', 'banana', 'cherry']
print(fruits, type(fruits))  # ['apple', 'banana', 'cherry'] <class 'list'>
Con una list, puedes cambiar sus elementos, agregar nuevos o eliminar los existentes:
fruits[1] = 'blueberry'       # Cambia 'banana' a 'blueberry'
fruits.append('dragonfruit')  # Agrega 'dragonfruit' al final de la lista
print(fruits)                 # ['apple', 'blueberry', 'cherry', 'dragonfruit']

Tipos Inmutables

Por otro lado, ejemplos de tipos inmutables son int, float, string y tuple. Una vez creados, no puedes cambiar su contenido. Aquí hay un ejemplo de un string:
message = 'hello'
print(message, type(message))  # hello <class 'str'>
Si intentas cambiar parte del string, Python no lo permitirá:
message[0] = 'H'  # Intentar cambiar 'h' por 'H' te dará un TypeError
¿Cómo es que int es inmutable? ¿No podemos cambiar el valor con += o -=?
Cuando hablamos de mutabilidad en Python, nos referimos a que el valor real almacenado en memoria puede ser modificado. Por ejemplo, cuando tenemos una lista, podemos cambiar un elemento de la lista y sigue siendo la misma lista en memoria.
Los enteros en Python son inmutables. Esto significa que el valor en memoria no puede ser cambiado. Si tenemos un entero, a = 5, y realizamos una operación como a += 2, podría parecer que cambiamos a. Sin embargo, lo que Python realmente hizo fue crear un nuevo objeto en memoria con un valor de 7 y actualizó a para que apunte a este nuevo objeto. El 5 original no fue cambiado en memoria, por eso los int se consideran inmutables.
a = 5
print(id(a))  # Esto imprime la ubicación en memoria de a. Digamos que es 1001

a += 2
print(a)      # Esto imprime 7
print(id(a))  # Esto imprimirá una ubicación de memoria diferente, digamos que es 1002
La función id en Python devuelve la identidad de un objeto, que es única y constante para el objeto durante su vida útil. Entonces, cuando vemos que la identidad de a cambió después de la operación a += 2, es una señal clara de que a ahora apunta a un nuevo objeto en memoria. El entero original 5 no fue cambiado, lo que confirma que los enteros son de hecho inmutables en Python.

Argumentos Mutables en Funciones

Cuando pasamos un objeto mutable (como una lista) a una función, Python le da a la función una referencia a ese objeto. Esto significa que si la función modifica el objeto mutable, esa modificación se verá también fuera de la función.
Usemos una función que recibe una lista y le agrega un elemento:
def add_item(my_list):
    my_list.append('added item')  # Agrega un nuevo elemento a la lista

shopping_list = ['apples', 'bananas', 'cherries']
print(shopping_list)  # Prints: ['apples', 'bananas', 'cherries']

# Ahora usamos la función para agregar un elemento a nuestra lista de compras
add_item(shopping_list)
print(shopping_list)  # Prints: ['apples', 'bananas', 'cherries', 'added item']
Como puedes ver, cuando imprimimos shopping_list después de llamar a la función add_item, la lista tenía un nuevo elemento. Esto sucedió aunque no modificamos directamente shopping_list fuera de la función.
Sin embargo, es importante entender que si asignas un nuevo valor a todo el objeto mutable dentro de la función, eso no afectará al objeto original. Esto se debe a que le estás dando a la variable local de la función una nueva referencia, no modificando el objeto original. Veamos un ejemplo de esto:
def change_list(my_list):
    my_list = ['entirely', 'new', 'list']  # Esto no afectará a la lista original

shopping_list = ['apples', 'bananas', 'cherries']
change_list(shopping_list)
print(shopping_list)  # Still prints: ['apples', 'bananas', 'cherries']
Aunque llamamos a la función change_list con shopping_list como argumento, el contenido de shopping_list no cambió. Eso es porque dentro de la función, my_list recibió una nueva referencia (a una lista completamente nueva), mientras que la referencia de shopping_list permaneció intacta.
La clave aquí es: cuando pasas un objeto mutable a una función en Python, recuerda que si la función cambia el objeto (como agregar un elemento a una lista), el cambio es permanente y se verá fuera de la función. Pero si le das un nuevo valor a todo el objeto dentro de la función, eso no afectará al objeto original.
 
To check your solution you need to sign in
Sign in to continue