Skip to content
Tutoriales
Python
Side_effect in Python - What It Is And How to Use?

Una breve explicación del efecto colateral en Python

En el mundo de la programación en Python, comprender y controlar adecuadamente los efectos colaterales es vital. Estos aspectos a menudo pasan desapercibidos pero son críticos, y pueden marcar la diferencia entre un programa que funciona bien y uno impredecible y difícil de mantener.

Los efectos colaterales en Python ocurren cuando una función, en lugar de simplemente devolver un valor, también modifica algún estado o tiene una interacción observable con el mundo exterior. Si bien no siempre son negativos, estos efectos colaterales pueden introducir errores que son difíciles de rastrear y solucionar. Por lo tanto, aprender a controlar o evitarlos puede mejorar significativamente la estabilidad y confiabilidad de su código.

¿Quieres crear rápidamente visualizaciones de datos a partir de un marco de datos de Python Pandas sin código?

PyGWalker es una biblioteca de Python para el análisis de datos exploratorio con visualización. PyGWalker (opens in a new tab) puede simplificar su flujo de trabajo de análisis y visualización de datos en Jupyter Notebook, convirtiendo su marco de datos de pandas (y marco de datos de polars) en una interfaz de usuario similar a Tableau para la exploración visual.

PyGWalker para visualización de datos (opens in a new tab)

¿Qué es un efecto colateral en Python?

En Python, un efecto colateral es cualquier cambio que una función realiza en su estado o en el estado del programa global, aparte de su valor de retorno. Los efectos colaterales pueden incluir la modificación de una variable global o estática, cambiar el objeto original, producir salida en la consola o escribir en un archivo o base de datos. Son comunes en operaciones como operaciones de entrada/salida, actualizaciones de estados globales o incluso en los métodos de clase que alteran el estado del objeto.

# Ejemplo de efecto colateral en Python
def add_element(data, element):
    data.append(element)
    return data
 
my_list = [1, 2, 3]
print(add_element(my_list, 4))  # Salida: [1, 2, 3, 4]
print(my_list)  # Salida: [1, 2, 3, 4]

En esta función add_element, tenemos un efecto colateral. La función no solo devuelve la lista actualizada, sino que también modifica la lista original my_list. Este es un ejemplo típico de efecto colateral en Python y uno de los principales errores de efectos colaterales a evitar al escribir código en Python.

Funciones puras en Python

En contraste, una función pura es aquella que, para la misma entrada, siempre produce la misma salida y no tiene efectos colaterales. La pureza de una función consiste en su naturaleza autocontenida, lo que la hace predecible y fácil de probar.

# Ejemplo de función pura en Python
def add_element_pure(data, element):
    new_list = data.copy()
    new_list.append(element)
    return new_list
 
my_list = [1, 2, 3]
print(add_element_pure(my_list, 4))  # Salida: [1, 2, 3, 4]
print(my_list)  # Salida: [1, 2, 3]

En este ejemplo, add_element_pure es una función pura. Crea una nueva lista basada en la entrada y luego agrega el nuevo elemento a esta lista. La lista original my_list permanece sin cambios. Comprender las características de las funciones puras en Python es fundamental para escribir código que sea robusto y más fácil de depurar.

Utilizando decoradores para controlar efectos colaterales

Los decoradores en Python ofrecen una forma poderosa de modificar el comportamiento de una función o clase. Al envolver la función o clase, un decorador puede ejecutar código antes o después de que se ejecute la función envuelta, sin cambiar su código fuente.

# Ejemplo de decorador en Python
def no_side_effects_decorator(func):
    def wrapper(*args, **kwargs):
        data_copy = args[0].copy()  # crear una copia de los datos
        return func(data_copy, *args[1:], **kwargs)
    return wrapper
 
@no_side_effects_decorator
def add_element(data, element):
    data.append(element)
    return data
 
my_list = [1, 2, 3]
print(add_element(my_list, 4))  # Salida: [1, 2, 3, 4]
print(my_list)  # Salida: [1, 2, 3]

En el fragmento de código anterior, el decorador no_side_effects_decorator envuelve la función add_element. Se asegura de usar una copia de los datos para las operaciones, dejando los datos originales sin cambios. Esta es una forma de utilizar decoradores en Python para controlar los efectos colaterales.

Prueba de efectos colaterales utilizando objetos simulados (mock objects)

La biblioteca unittest.mock en Python es una herramienta poderosa para escribir pruebas. Le permite reemplazar partes del sistema que se está probando y hacer afirmaciones sobre cómo se han utilizado. La biblioteca unittest.mock también proporciona una clase Mock que se puede utilizar para crear un objeto simulado (mock object).

En las pruebas unitarias en Python, uno de los usos comunes de los objetos simulados es probar el comportamiento del código en condiciones controladas. Por ejemplo, cuando una función llama a otra función (que puede tener efectos colaterales), un objeto simulado puede simular la función llamada, evitando los efectos colaterales.

from unittest.mock import Mock
 
# Función original que vamos a simular
def add_element(data, element):
    data.append(element)
    return data
 
# Objeto simulado (mock object)
add_element = Mock(side_effect=lambda data, element: data + [element])
 
# Prueba con el objeto simulado
my_list = [1, 2, 3]
print(add_element(my_list, 4))  # Salida: [1, 2, 3, 4]
print(my_list)  # Salida: [1, 2, 3]

En este ejemplo, add_element es una función que agrega un elemento a una lista, causando un efecto colateral. Pero cuando reemplazamos add_element con un objeto simulado, simula la función sin el efecto colateral. Este es un ejemplo de cómo utilizar objetos simulados en Python para controlar los efectos colaterales.

La biblioteca unittest.mock también proporciona la función patch, que se puede utilizar para reemplazar los objetos reales en su código con instancias simuladas durante las pruebas. El 'parche' se deshace automáticamente después de que finaliza la prueba.

En la próxima parte del artículo, discutiremos más sobre la biblioteca de parche en Python y exploraremos más ejemplos de objetos simulados en Python. También profundizaremos en las características de las funciones puras en Python y veremos más ejemplos de decoradores en Python para controlar los efectos colaterales. Manténgase atento para aprender cómo utilizar el parche en Python y cómo evitar errores comunes al tratar con los efectos colaterales en Python.

Utilizando la biblioteca Patch en Python

La biblioteca Patch en Python, específicamente unittest.mock.patch, le permite controlar el alcance del objeto simulado (mock) y determinar cuándo se reemplaza el objeto original y cuándo se restaura. Es especialmente útil para pruebas unitarias donde se desea simular el comportamiento de un objeto durante una prueba y luego hacer que el objeto simulado se elimine automáticamente después de que la prueba haya finalizado.

from unittest.mock import patch
 
def add_element(data, element):
    data.append(element)
    return data
 
def test_add_element():
    with patch('__main__.add_element', side_effect=lambda data, element: data + [element]):
        my_list = [1, 2, 3]
        print(add_element(my_list, 4))  # Salida: [1, 2, 3, 4]
        print(my_list)  # Salida: [1, 2, 3]
 
test_add_element()

En este fragmento de código, la función add_element se reemplaza temporalmente dentro del alcance de la declaración with. Después de ejecutar la función de prueba, se restaura el add_element original.

Estructuras de datos inmutables y efectos colaterales

Las estructuras de datos inmutables son otra herramienta que ayuda a controlar los efectos colaterales en Python. Por definición, un objeto inmutable no puede cambiarse después de haber sido creado. En Python, ejemplos de estructuras de datos inmutables incluyen tuplas, cadenas y conjuntos congelados (frozensets).

Cuando se utilizan estructuras de datos inmutables, cualquier operación que modifique los datos en lugar de eso creará un nuevo objeto. Esto ayuda a evitar los efectos colaterales, ya que los datos originales permanecen sin cambios.

# La tupla en Python es inmutable
my_tuple = (1, 2, 3)
new_tuple = my_tuple + (4,)  # Crear una nueva tupla
print(new_tuple)  # Salida: (1, 2, 3, 4)
print(my_tuple)  # Salida: (1, 2, 3)

En este ejemplo, my_tuple es una tupla, que es una estructura de datos inmutable en Python. Cuando intentamos agregar un elemento, se crea una nueva tupla new_tuple, y my_tuple permanece sin cambios.

Conclusión

Gestionar los efectos colaterales en Python es un aspecto importante para escribir código de alta calidad y fácil de mantener. Al comprender y aprovechar los conceptos de las funciones puras, los decoradores y las estructuras de datos inmutables, así como dominar el uso de objetos simulados y bibliotecas de parche, puede mantener su código Python libre de efectos colaterales innecesarios. Esto no solo hace que su código sea más confiable, sino también más fácil de probar y depurar, lo que resulta en aplicaciones Python de mayor calidad.

Preguntas frecuentes

Veamos ahora algunas preguntas frecuentes:

  1. ¿Qué es un efecto colateral en Python?
    Un efecto colateral en Python es cualquier cambio que una función realiza en el estado del programa o en su propio estado, aparte del valor que devuelve. Los efectos colaterales pueden incluir la modificación de una variable global o estática, la modificación del objeto original, la producción de resultados en la consola o la escritura en un archivo o base de datos.

  2. ¿Por qué debes evitar los efectos colaterales en Python?
    Los efectos colaterales en Python, aunque no siempre son perjudiciales, pueden introducir errores que son difíciles de rastrear y solucionar. Pueden hacer que su código sea impredecible y difícil de analizar. Al evitar los efectos colaterales, se logra un código más estable, predecible y fácil de probar.

  3. ¿Qué es una función pura en Python?
    Una función pura en Python es aquella que siempre produce la misma salida para la misma entrada y no tiene efectos colaterales. Las funciones puras son autocontenidas, lo que las hace predecibles y fáciles de probar.