Gestor de Contexto en Python

PythonBeginner
Practicar Ahora

Introducción

Aunque los gestores de contexto (context managers) de Python son ampliamente utilizados, pocos comprenden el propósito detrás de su uso. Estas sentencias, comúnmente empleadas al leer y escribir archivos, ayudan a la aplicación a conservar la memoria del sistema y mejoran la gestión de recursos al asegurar que recursos específicos solo estén en uso para ciertos procesos.

En este laboratorio, aprenderá a utilizar la sentencia with para la gestión automática de recursos, y luego creará sus propios gestores de contexto utilizando dos métodos diferentes: un enfoque basado en funciones y un enfoque basado en clases.

La sentencia with

En este paso, aprenderás a usar la sentencia with con gestores de contexto (context managers) como los objetos de archivo. Un gestor de contexto es un objeto al que se le notifica cuando un contexto (un bloque de código) comienza y termina. La sentencia with se encarga de este proceso de notificación automáticamente.

Por ejemplo, los objetos de archivo son gestores de contexto. Cuando finaliza un bloque with, el objeto de archivo se cierra automáticamente, incluso si ocurren errores dentro del bloque. Esto previene la pérdida de datos y las fugas de recursos.

Nota: Si no estás familiarizado con el uso de WebIDE (similar a VS Code), por favor, apréndelo primero en este laboratorio.

Veamos esto en acción. En el explorador de archivos de la izquierda, abre el archivo main.py. Copia y pega el siguiente código en él. Este código primero creará y escribirá en un archivo, y luego leerá su contenido, todo usando la sentencia with.

## Crearemos un archivo para demostrar la sentencia 'with'.
## Primero, escribamos algo de contenido en un archivo.
with open('my_file.txt', 'w') as f:
    f.write('This is a test file.')

## Ahora, lo leeremos de nuevo usando un gestor de contexto.
## El archivo se cierra automáticamente al salir del bloque 'with'.
with open('my_file.txt') as f:
    file_contents = f.read()
    print(file_contents)

## El archivo se cierra automáticamente aquí, incluso si ocurrió un error.
print("\nFile has been read and closed.")

Ahora, ejecuta el script desde la terminal para ver la salida.

python3 main.py

Deberías ver la siguiente salida, confirmando que el archivo se escribió y se leyó con éxito. La sentencia with asegura que my_file.txt se cierre correctamente después de ambas operaciones de escritura y lectura.

This is a test file.

File has been read and closed.

Usar una sentencia with es la forma recomendada para manejar recursos como archivos o conexiones de red porque hace que tu código sea más limpio y seguro.

Escribir su propio gestor de contexto

En este paso, descubrirá cómo crear un gestor de contexto personalizado utilizando una función generadora (generator function) y el decorador @contextlib.contextmanager. Esta es una forma concisa de crear gestores de contexto simples.

El código antes de la sentencia yield se ejecuta al entrar en el bloque with (la lógica de configuración o setup), y el código después de la sentencia yield se ejecuta al salir de él (la lógica de limpieza o cleanup). El valor que se genera (yielded) puede asignarse a una variable usando la palabra clave as en la sentencia with.

Abra el archivo function_cm.py en el explorador de archivos. Copie el siguiente código en el archivo.

## Gestor de contexto basado en funciones usando el decorador contextlib
import contextlib

@contextlib.contextmanager
def context_manager(num):
    print('Enter')  ## El código antes de yield se ejecuta en __enter__
    yield num + 1   ## El valor generado se convierte en la variable 'cm'
    print('Exit')    ## El código después de yield se ejecuta en __exit__

with context_manager(2) as cm:  ## cm recibe el valor generado (3)
    print('Right in the middle with cm = {}'.format(cm))

Ahora, ejecute el script en la terminal.

python3 function_cm.py

Verá la siguiente salida. Observe el orden de ejecución: el código antes de yield se ejecuta primero, luego el código dentro del bloque with, y finalmente el código después de yield.

Enter
Right in the middle with cm = 3
Exit

Este enfoque es muy útil para crear contextos temporales, como configurar y desmantelar una conexión a base de datos o cambiar temporalmente una configuración.

Gestor de contexto basado en clases

En este paso, implementará un gestor de contexto como una clase. Este enfoque proporciona más control y es adecuado para escenarios más complejos. Para crear un gestor de contexto basado en clases, debe definir dos métodos especiales: __enter__ y __exit__.

  • __enter__: Este método se llama al entrar en la sentencia with. Debe realizar la lógica de configuración (setup). Su valor de retorno se asigna a la variable después de as, si se proporciona.
  • __exit__: Este método se llama al salir del bloque with, ya sea de forma normal o debido a una excepción. Debe realizar la lógica de limpieza (cleanup).

Creemos uno. Abra el archivo class_cm.py y copie el siguiente código en él.

## Gestor de contexto basado en clases: implementa los métodos __enter__ y __exit__
class ContextManager:
    def __enter__(self, *args, **kwargs):  ## Se llama al entrar en el bloque 'with'
        print("--enter--")
        return self  ## Puede devolver el objeto para usarlo como variable 'as'

    def __exit__(self, *args):  ## Se llama al salir del bloque 'with'
        print("--exit--")

with ContextManager():  ## Llama a __enter__, luego a __exit__ cuando termina
    print("test")

Ejecute el script desde la terminal.

python3 class_cm.py

La salida demuestra el flujo de control. El método __enter__ se llama primero, seguido del código dentro del bloque with, y finalmente, se llama al método __exit__ para la limpieza.

--enter--
test
--exit--

El enfoque basado en clases es potente porque le permite encapsular lógica compleja de configuración y desmantelamiento (teardown) dentro de un único objeto reutilizable.

Resumen

¡Felicidades por completar el laboratorio! Ha aprendido a gestionar recursos de manera efectiva en Python utilizando gestores de contexto (context managers).

Comenzó con la declaración común with para la manipulación segura de archivos. Luego, pasó a crear sus propios gestores de contexto personalizados utilizando dos métodos diferentes:

  • Un enfoque basado en funciones con el decorador @contextlib.contextmanager, que es excelente para tareas simples de configuración y desmantelamiento (setup y teardown).
  • Un enfoque basado en clases implementando los métodos __enter__ y __exit__, que es ideal para una gestión de recursos más compleja.

Estas habilidades son cruciales para escribir código Python limpio, confiable y eficiente que maneje los recursos adecuadamente.