ProgramaciónDesarrollador Backend Python

¿Cómo funciona el administrador de contexto en Python, para qué sirve y cómo se puede implementar uno propio a través de los protocolos __enter__ y __exit__? ¿Qué aspectos importantes se deben tener en cuenta?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Administrador de contexto — es un objeto que define el comportamiento de entrada y salida de un bloque with, asegurando la gestión automática de recursos (archivos, conexiones, etc.). Se implementa mediante los métodos __enter__ y __exit__ en una clase o a través del decorador @contextmanager del módulo contextlib.

Ejemplo de implementación:

class FileManager: def __init__(self, filename, mode): self.filename = filename self.mode = mode self.file = None def __enter__(self): self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): if self.file: self.file.close() with FileManager('test.txt', 'w') as f: f.write('Hello')

Aspectos a tener en cuenta: Es importante manejar las excepciones correctamente en __exit__, retornando True para suprimir errores, y tener cuidado con los recursos para no dejarlos abiertos en caso de errores.

Pregunta capciosa.

Pregunta: Si ocurre una excepción dentro del bloque with, ¿llama Python al método __exit__? ¿Cómo se pasan los parámetros de error?

Respuesta: Sí, el método __exit__ siempre se llama, incluso si ocurre una excepción. Los tipos de la excepción, su valor y el traceback se pasan como argumentos. Si __exit__ devuelve True, la excepción se suprime.

class Simple: def __enter__(self): print('Entrar') def __exit__(self, exc_type, exc_val, exc_tb): print('Salir') print(exc_type, exc_val) return True # el error no "sale" afuera with Simple(): raise ValueError('¡boom!')

Ejemplos de errores reales por desconocer los detalles del tema.


Historia

Olvidaron implementar __exit__ en un administrador de contexto personalizado para manejar descriptores de archivos — en caso de excepción el archivo no se cerraba, lo que provocaba fugas de descriptores de archivos y fallos al trabajar con muchas archivos.

Historia

Usaron un administrador de contexto de terceros para gestionar la base de datos, que devolvía True en __exit__ para todas las excepciones. Esto "silenciaba" errores y provocaba fallos indetectables y la corrupción de datos, ya que la lógica asumía que la transacción había sido exitosa.

Historia

Usaron el decorador @contextmanager del módulo contextlib, pero olvidaron manejar excepciones dentro de yield, por lo que la conexión de socket permanecía abierta en caso de fallo del código y el servidor "se colgó" con puertos abiertos.