Como Entender la Sentencia "WITH" de Python



A juzgar por comp.lang.python y otros foros, la nueva sentencia "WITH" de Python 2.5 parece ser un poco confusa, incluso para los programadores experimentados de Python. Como la mayoría de las otras cosas en Python, la declaración with es en realidad muy simple, una vez que entienda el problema que está tratando de resolver. Considere este pedazo de código:

    configurar las cosas
    try:
        hacer algo
    finally:
        liberar las cosas

Aquí, "configurar las cosas" podría ser la apertura de un archivo, o la adquisición de algún tipo de recurso externo, y "liberar las cosas" sería entonces el cierre del archivo, o liberar o eliminar el recurso. La construcción try-finally garantiza que la parte "liberar las cosas" siempre se ejecuta, incluso si el código que realiza el trabajo no termina.

Si haces esto muy seguido, sería muy conveniente si pudieras poner el código "configurar las cosas" y "liberar las cosas" en una función de biblioteca, para que sea fácil de reutilizar. Por supuesto, puedes hacer algo como

 def  ejecucion_controlada(callback):
        configurar las cosas
        try:
            callback(cosas)
        finally:
            liberar las cosas

  def  mi_funcion (cosas):
      hacer algo

  ejecucion_controlada(mi_funcion)

Pero eso es demasiado detallado, especialmente si necesita modificar variables locales. Otro enfoque consiste en utilizar un generador de un disparo y utilizar la sentencia for-in para "envolver" el código:

    def  ejecucion_controlada():
        configurar las cosas
        try:
            yield cosa
        finally:
            liberar las cosas

    for cosa in ejecucion_controlada():
        hacer algo with cosa




Pero yield ni siquiera se permite dentro de un try-finally en 2.4 y anteriores. Y mientras que podría ser arreglado (y se ha arreglado en 2.5), sigue siendo un poco extraño utilizar una construcción de bucle cuando sabes que sólo desea ejecutar algo una vez.


Así que después de contemplar una serie de alternativas, GvR y el equipo python-dev finalmente desarrollaron una generalización de este último, utilizando un objeto en lugar de un generador para controlar el comportamiento de una pieza externa de código:

   class ejecucion_controlada:
         def  __enter__ (self):
            configurar las cosas
            return cosa
         def  __exit__ (self, type, value, traceback):
            liberar las cosas

    with ejecucion_controlada() as cosa:
         codigo...

Ahora, cuando se ejecuta la instrucción "with", Python evalúa la expresión, llama al método __enter__ del valor resultante (que se denomina "guardia de contexto") y asigna lo que __enter__ devuelve a la variable dada por as. Python ejecutará entonces el cuerpo del código, y pase lo que pase en ese código, llama al método __exit__ del objeto guardia.

Como bono adicional, el método __exit__ puede ver la excepción, si la hay, y suprimirla o actuar en ella según sea necesario. Para suprimir la excepción, simplemente devuelva un valor verdadero. Por ejemplo, el siguiente método __exit__ traga cualquier TypeError, pero deja todas las demás excepciones a través de:


  def  __exit__ (self, type, value, traceback):
         return isinstance(value, TypeError)


( Te puede interesar: Porqué creó Google el lenguaje Go? ¿No era suficiente con Python? )

En Python 2.5, el objeto de archivo se ha equipado con los métodos __enter__ y __exit__ ; el primero simplemente devuelve el objeto del archivo en sí, y el último cierra el archivo:

    >>> f = open( "x.txt" )
    >>> f
    <archivo abierto 'x.txt' , modo 'r' en 0x00AE82F0>
    >>> f.__ enter __()
    <Archivo abierto 'x.txt' , modo 'r' en 0x00AE82F0>
    >>> f.read(1)
    'X'
    >>> f.__ exit __(None, None, None)
    >>> f.read(1)
    Traceback (most recent call last):
      File "<stdin>" , linea 1, in <module>
    ValueError: Operacion de E/S en archivo cerrado

Así que para abrir un archivo, procesar su contenido y cerciorarse de cerrarlo, usted puede hacer simplemente:

  with open( "x.txt" ) as f:
    datos = f.read()
    hacer algo con datos


¿Y ahora ya entiendes como se usa "WITH"? Déjalo en los comentarios.

2 comentarios:

  1. gracias, me ayudo a comprender un poco, aclaro soy novato en esto de la programación

    ResponderEliminar
  2. Una pregunta tomando tu mismo ejemplo
    with open( "x.txt" ) as f:
    datos = f.read()

    Cómo Puedo volver sobre los valores de datos en otro momento del programa. Es decir puedo sacarlos del ciclo with

    ResponderEliminar