es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Hay alguna versión de contextlib.contextmanager para clases en Python?

Utilizar generadores como bloques de construcción para los gestores de contexto es un enfoque interesante porque mantiene todo el estado en un solo lugar. Por ejemplo:

@contextlib.contextmanager
def manager():
    state = get_state() 
    try:
        yield f(state)
    except Exception:
        handle(state)
    finally:
        cleanup(state)

Sin embargo, un patrón común es el siguiente:

class Cliente():
   ...

with Cliente() as c:
    c.blah()

Esto no se presta para el uso de gestores de contexto porque Cliente llama a __init__.

¿Existe alguna forma de definir una clase, pero aún así usar generadores para definir el código de __enter__ y __exit__?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, es posible definir una clase y aún así utilizar generadores para definir el código __enter__ y __exit__ mediante la implementación de contextlib.ContextDecorator. Este decorador permite convertir un gestor de contexto basado en generador en un gestor de contexto basado en clase que puede ser utilizado como un decorador. Aquí hay un ejemplo:

    from contextlib import ContextDecorator
    
    class manager(ContextDecorator):
        def __init__(self):
            self.state = get_state()
    
        def __enter__(self):
            return self.state
    
        def __exit__(self, exc_type, exc_value, traceback):
            if exc_type is not None:
                handle(self.state)
            cleanup(self.state)
            return False
    

    Ahora puedes usar esta clase como un decorador como tal:

    @manager()
    def my_function():
        # Código a ser ejecutado bajo el gestor de contexto
    
    with my_function():
        # Hacer algo con el estado devuelto por __enter__()
    

    Esto te permite definir un gestor de contexto basado en clase con generadores y aún así utilizarlo como un decorador, igual que con los gestores de contexto basados en función.

Comments are closed.