Gestores de contexto
Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 41 de 64.
Los administradores de contexto te permiten asignar y liberar recursos justo cuando los necesitas. Garantizan una limpieza adecuada incluso si se producen errores.
Aquí tienes el ejemplo más común de uso de la instrucción with:
with open('example.txt', 'w') as file:
file.write('Hello, world!')
# El archivo se cierra automáticamente aquíEl archivo se cierra automáticamente después del bloque, incluso si se produce una excepción.
Crea tu propio gestor de contexto implementando los métodos __enter__ y __exit__:
class MyContext:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exiting the context")
return False # No suprimas las excepcionesUsa tu administrador de contexto personalizado:
with MyContext() as ctx:
print("Inside the context")Salida:
Entering the context
Inside the context
Exiting the contextCrea un administrador de contexto más práctico para las conexiones a bases de datos:
class DatabaseConnection:
def __init__(self, db_name):
self.db_name = db_name
self.connection = None
def __enter__(self):
print(f"Connecting to {self.db_name}")
self.connection = f"Connection to {self.db_name}"
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
print(f"Closing connection to {self.db_name}")
self.connection = None
with DatabaseConnection("users_db") as conn:
print(f"Using {conn}")
print("Performing database operations...")Maneja las excepciones en los administradores de contexto:
class SafeContext:
def __enter__(self):
print("Setting up resources")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Cleaning up resources")
if exc_type:
print(f"An exception occurred: {exc_val}")
return False # No suprimas la excepción
with SafeContext():
print("Working with resources")
# raise ValueError("Something went wrong") # Descomenta para probarSalida:
Connecting to users_db
Using Connection to users_db
Performing database operations...
Closing connection to users_db
Setting up resources
Working with resources
Cleaning up resourcesEl método __exit__ recibe tres parámetros:
exc_type: Tipo de excepción (o None)exc_val: Valor de la excepción (o None)exc_tb: Traza de la excepción (o None)
Punto clave: Los gestores de contexto usan los métodos __enter__ y __exit__ para gestionar recursos. La instrucción with llama automáticamente a estos métodos, lo que garantiza una configuración y una limpieza adecuadas. Esto resulta especialmente útil para archivos, conexiones a bases de datos y otros recursos que requieren una limpieza garantizada.
Desafío
FácilEn este desafío, implementarás una clase de administrador de contexto que mide el tiempo transcurrido entre la entrada y la salida de un bloque de contexto.
timer.py- Contiene la implementación de la claseTimer(este es el archivo que editarás)driver.py- Contiene casos de prueba exhaustivos (no lo modifiques)
Implementa el administrador de contexto Timer en timer.py siguiendo los comentarios TODO. La clase debe:
- Registrar la hora de inicio al entrar en un contexto
- Registrar la hora de finalización al salir
- Calcular y mostrar el tiempo transcurrido
Pruébalo tú mismo
from timer import Timer
import time
# Gestor de casos de prueba
test_case = input()
if test_case == "basic_test":
# Prueba de funcionalidad básica
with Timer():
# Simular algo de trabajo
time.sleep(2) # Esto hace que el programa espere 2 segundos
elif test_case == "nested_contexts":
# Probar gestores de contexto anidados
with Timer():
time.sleep(1)
with Timer():
time.sleep(1)
elif test_case == "exception_handling":
# Probar el manejo de excepciones dentro del contexto
try:
with Timer():
time.sleep(1)
raise ValueError("Test exception")
except ValueError as e:
print(f"Caught exception: {e}")
elif test_case == "zero_sleep":
# Probar con una pausa mínima
with Timer():
time.sleep(0.001)
elif test_case == "multiple_timers":
# Probar varios temporizadores en secuencia
with Timer():
time.sleep(1)
with Timer():
time.sleep(0.5)
with Timer():
time.sleep(2)
elif test_case == "as_decorator":
# Probar el temporizador en el contexto de una función
def timed_function():
with Timer():
time.sleep(2)
timed_function()
else:
# Prueba predeterminada - funcionalidad básica
with Timer():
# Simular algo de trabajo
time.sleep(2) # Esto hace que el programa espere 2 segundos
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de la POO
Introducción a la POOArchivos externosClases vs. objetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Repaso: calculadora sencilla4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosRepaso: jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso: lista personalizada10Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy2Decoradores
Introducción a los decoradoresDecorador de propiedadDecorador de método estáticoDecorador de método de clase5Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas8Conceptos avanzados de POO
Composición frente a herenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs. variables de claseDecoradores de propiedadesAtributos privadosRepaso: gestor de cuentas bancariasPractica por tu cuenta: Compilador de Python online