ProgramaciónDesarrollador Backend

¿Qué es la transmisión de argumentos por referencia y por valor en Python? ¿Cómo implementa Python este mecanismo y por qué es importante diferenciarlos al diseñar funciones?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Entender cómo Python pasa argumentos a las funciones es crucial para prevenir cambios inesperados en los datos y para un correcto diseño del código.

Historia de la cuestión

En lenguajes de programación tradicionales como C o Java, se utiliza la transmisión por valor (copy by value) o por referencia (copy by reference). Sin embargo, Python tiene un modelo diferente: call by object reference (a veces llamado "call by sharing").

Problema

Muchos desarrolladores erróneamente piensan que Python siempre pasa argumentos por referencia o por valor. Esto inevitablemente conduce a situaciones en las que los objetos mutables se modifican inesperadamente en el código que llama.

Solución

En Python, los valores de los parámetros de la función son referencias a los objetos que se pasan a la función. Esto significa:

  • Si el objeto es mutable (mutable: list, dict, set…) — dentro de la función se puede modificar, y esto se reflejará externamente.
  • Si el objeto es inmutable (immutable: int, str, tuple, frozenset), intentar cambiarlo dentro de la función resultará en la creación de un nuevo objeto y no afectará al externo.

Ejemplo:

# list - mutable def add_item(lst): lst.append(42) my_list = [1, 2, 3] add_item(my_list) print(my_list) # [1, 2, 3, 42] # int - inmutable def add_num(x): x = x + 1 num = 10 add_num(num) print(num) # 10

Características clave:

  • Los objetos mutables pueden ser cambiados dentro de la función — estos cambios son visibles externamente.
  • Los objetos inmutables no son tocados por la función — solo se crean nuevos objetos.
  • Python nunca copia argumentos automáticamente, incluso las estructuras mutables siempre se pasan "por referencia".

Preguntas con trampa.

¿Se pasan siempre argumentos por referencia en Python?

No, en Python se pasan referencias a los objetos, y cómo se comporta el objeto depende de si es mutable o no. Un objeto inmutable creará un nuevo objeto con cualquier cambio.

¿Se puede reasignar un argumento mutable en la función de manera que afecte al objeto externo?

No. Si dentro de la función asignas un nuevo valor a un parámetro, el objeto externo no cambiará — solo estás cambiando la referencia local.

Ejemplo:

def reassign_list(lst): lst = [99, 100] my_list = [1, 2, 3] reassign_list(my_list) print(my_list) # [1, 2, 3]

¿Por qué una función que recibe una lista por defecto puede comportarse de manera extraña en llamadas sucesivas?

Porque el valor por defecto se crea una sola vez — al definir la función, y si se modifica (por ejemplo, añadiendo un elemento), se cambiará para todas las llamadas posteriores.

def add_element(x, cache=[]): cache.append(x) return cache print(add_element(1)) # [1] print(add_element(2)) # [1, 2]

Errores típicos y anti-patrones

  • Uso de argumentos mutables por defecto (como en el último ejemplo).
  • Esperar que la función no modifique la lista o diccionario pasado, aunque lo haga.
  • Confusión de los efectos de las funciones al trabajar con objetos mutables e inmutables.

Ejemplo de la vida real

Caso negativo

Un programador pasa una lista a la función y espera que su lista original no cambie, pero la función añade un elemento.

Pros:

  • Rápido funcionamiento, sin copia de datos.

Contras:

  • Efectos secundarios inesperados, errores en código grande, si alguien no conoce las modificaciones del argumento.

Caso positivo

Un programador copia explícitamente la lista dentro de la función, si necesita devolver algo, pero no cambiar el original:

def process_data(data): data = data.copy() # o list(data) # trabajo seguro con la copia data.append('informe') return data

Pros:

  • Sin efectos secundarios indeseados, el original está protegido.

Contras:

  • En objetos grandes — costos de memoria/tiempo por copia.