Pregunta

Soy nuevo en esto, y estoy tratando de entender la declaración with. Yo entiendo que se supone que debe reemplazar el / bloque try except.

Ahora supongamos que hago algo como esto:

try:
   name='rubicon'/2 # to raise an exception
except Exception as e:
   print "no not possible"
finally:
   print "Ok I caught you"

¿Cómo se sustituye esto con un gestor de contexto?

¿Fue útil?

Solución

with en realidad no sustituir try / except, sino, más bien, try / finally. Aún así, puede hacer un gestor de contexto hacer algo diferente en los casos de excepción de los no excepción:

class Mgr(object):
    def __enter__(self): pass
    def __exit__(self, ext, exv, trb):
        if ext is not None: print "no not possible"
        print "OK I caught you"
        return True

with Mgr():
    name='rubicon'/2 #to raise an exception

La parte return True es donde el gestor de contexto decide suprimir la excepción (como lo hace por no volver a levantar en su cláusula except).

Otros consejos

El contextlib.contextmanager función decoradora proporciona una forma práctica de proporcionar un gestor de contexto y sin la necesidad de escribir una clase ContextManager de pleno derecho de su propio (con métodos __enter__ y __exit__, por lo que no tiene que recordar los argumentos para el método __exit__, o que el __exit__ método debe return True el fin de suprimir la excepción). En su lugar, se escribe una función con un solo yield en el punto que desea que el bloque de with que ejecuta y atrapar cualquier excepciones (que efectivamente provienen de la yield) como lo haría normalmente.

from contextlib import contextmanager
@contextmanager
def handler():
    # Put here what would ordinarily go in the `__enter__` method
    # In this case, there's nothing to do
    try:
        yield # You can return something if you want, that gets picked up in the 'as'
    except Exception as e:
        print "no not possible"
    finally:
        print "Ok I caught you"

with handler():
    name='rubicon'/2 #to raise an exception

¿Por qué ir a la dificultad adicional de escribir un gestor de contexto? La reutilización de código. Puede utilizar el mismo gestor de contexto en múltiples lugares, sin tener que duplicar el manejo de excepciones. Si el manejo de excepciones es aplicable sólo a esa situación, entonces no se moleste con un gestor de contexto. Pero si el mismo patrón surge una y otra vez (o si puede para sus usuarios, por ejemplo, el cierre de un archivo, el desbloqueo de un mutex), vale la pena la molestia adicional. Es también un patrón ordenado de usar si el manejo de excepciones es un poco complicado, ya que separa la manipulación de la línea principal de flujo de código de excepción.

El with en Python está destinado a envolver un conjunto de estados donde se debe configurar y destruir o recursos cercanos. Es de una manera similar a try...finally a este respecto como el finalmente cláusula será ejecutado incluso después de una excepción.

Un gestor de contexto es un objeto que implementa dos métodos: __enter__ y __exit__. Se llaman inmediatamente antes y después (respectivamente) del bloque with.

Por ejemplo, echar un vistazo al ejemplo clásico open():

with open('temp.txt', 'w') as f:
    f.write("Hi!")

Open devuelve un objeto File que implementa __enter__ más o menos como return self y __exit__ como self.close().

Los componentes de gestor de contexto

  1. Usted debería implementar un __ método de introducir __ que devuelve un objeto
  2. Implementar un __ salida método __.

Ejemplo

Me va a dar un ejemplo sencillo para mostrar por qué necesitamos un gestor de contexto. Durante el invierno de Xinjiang, China, debe cerrar una puerta inmediatamente cuando se abre una puerta. si se olvida de cerrarla, obtendrá frío.

 class Door:
     def __init__(self):
         self.doorstatus='the door was closed when you are not at home'
         print(self.doorstatus)
     def __enter__(self):
         print('I have opened the door')
         return self
     def __exit__(self,*args):
         print('pong!the door has closed')
     def fetchsomethings(self):
         print('I have fetched somethings')

al buscar las cosas en su casa, usted debe abrir una puerta, ir a buscar algunas cosas y cerca de la puerta.

 with Door() as dr:
     dr.fetchsomethings()

la salida es:

the door was closed when you are not at home
I have opened the door
I have fetched somethings
pong!the door has closed

Explicación

cuando inicia una clase de puerta, se llamará __ init __ método que se imprimirá "La puerta estaba cerrada cuando no está en casa" y __ __ introducir método que va a imprimir "He abierto la puerta" y devolver una instancia lado llamado dr. cuando la llamada self.fetchsomethings en cuestión con el bloque, el método imprimirá "Tengo algunas cosas inverosímiles" .cuando el bloque es finished.the gestor de contexto invocará __ __ salida método y se imprimirá "pong! la puerta se ha cerrado" .cuando no se utiliza con palabra clave, __ __ introducir y __ __ salida no se invocará !!!!

declaraciones with o gestores de contexto están ahí para ayudar con la recursos (aunque puede ser utilizado para mucho más).

Digamos que ha abierto un archivo para escribir:

f = open(path, "w")

Ahora tiene un identificador de archivo abierto. Durante la tramitación de su expediente, ningún otro programa se puede escribir en él. Con el fin de permitir que otros programas de escribir en él, debe cerrar el identificador de archivo:

f.close()

Sin embargo, antes de cerrar el archivo se produjo un error:

f = open(path, "w")
data = 3/0  # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()

¿Qué va a pasar ahora es que la función o el programa entero saldrán, sin cambiar el archivo con un identificador abierto. (CPython limpia asas de terminación y mangos son liberados junto con un programa pero no se debe contar con eso)

A con la declaración asegura que en cuanto dejas de sangría, se va a cerrar el identificador de archivo:

with open(path, "w") as f:
    data = 3/0  # Tried dividing by zero. Raised ZeroDivisionError
    f.write(data)
# In here the file is already closed automatically, no matter what happened.

with declaraciones se pueden usar para muchas más cosas. Por ejemplo: threading.Lock()

lock = threading.Lock()
with lock:  # Lock is acquired
   do stuff...
# Lock is automatically released.

Casi todo lo hecho con un gestor de contexto se puede hacer con try: ... finally: ... , pero gestores de contexto son más agradable de usar, más cómodo, más fácil de leer y mediante la realización __enter__ y __exit__ proporcionan una interfaz fácil de usar.


Creación de gestores de contexto se realiza mediante la aplicación de __enter__() y < a href = "https://docs.python.org/3/reference/datamodel.html#object.__exit__" rel = "noreferrer"> __exit__() en una clase normal.

__enter__() dice lo que hay que hacer cuando un gestor de contexto se inicia y __exit__() cuando un gestor de contexto existe (dando la excepción al método __exit__() si se ha producido una excepción)

Un acceso directo para la creación de gestores de contexto se puede encontrar en contextlib . Se envuelve un generador como un gestor de contexto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top