Post Top Ad

Your Ad Spot

martes, 25 de junio de 2019

Gestores de contexto de Python

Introducción

Una de las características más "oscuras" de Python que utilizan casi todos los programadores de Python, incluso los principiantes, pero que realmente no comprenden, son los administradores de contexto . Probablemente los haya visto en forma de withdeclaraciones, que generalmente se encuentran por primera vez cuando aprende a abrir archivos en Python. Aunque los gestores de contexto parecen un poco extraños al principio, cuando realmente nos sumergimos en ellos, entendemos la motivación y las técnicas detrás de esto, tenemos acceso a una nueva arma en nuestro arsenal de programación. Así que sin más preámbulos, vamos a sumergirnos en él!

Motivación: Gestión de recursos.

Como alguien mucho más sabio que yo dijo, "La necesidad es la madre de la invención". Para entender realmente qué es un administrador de contexto y cómo podemos usarlo, primero debemos investigar las motivaciones detrás de él, las necesidades que dieron origen a este "invento".
La motivación principal detrás de los gestores de contexto es la gestión de recursos. Cuando un programa quiere obtener acceso a un recurso en la computadora, le pide al SO que lo haga, y el SO, a su vez, le proporciona un identificador para ese recurso. Algunos ejemplos comunes de tales recursos son archivos y puertos de red. Lo que es importante comprender es que estos recursos tienen una disponibilidad limitada, por ejemplo, un solo proceso a la vez puede usar un puerto de red y hay un número limitado de puertos disponibles. Así que cada vez que abrimos un recurso, debemos recordar cerrarlo , para que el recurso se libere. Pero desafortunadamente, es más fácil decirlo que hacerlo.
La forma más directa de lograr una administración de recursos adecuada sería llamar a la closefunción una vez que hayamos terminado con el recurso. Por ejemplo:
opened_file = open('readme.txt')  
text = opened_file.read()  
...
opened_file.close()  
Aquí abrimos un archivo con el nombre readme.txt, leemos el archivo y guardamos su contenido en una cadena text, y cuando terminamos, cerramos el archivo llamando al close()método del opened_fileobjeto. Ahora, a primera vista, esto puede parecer correcto, pero en realidad, no es en absoluto robusto. Si ocurre algo inesperado entre abrir el archivo y cerrar el archivo, lo que provocará que el programa no ejecute la línea que contiene la closeinstrucción, se producirá una fuga de recursos. Estos eventos inesperados son lo que llamamos exceptions, uno común sería cuando alguien cierra el programa a la fuerza mientras se está ejecutando.
Ahora, la forma correcta de manejar esto sería usando el manejo de Excepciones , usandotry...elsebloques. Mira el siguiente ejemplo:
try:  
    opened_file = open('readme.txt')
    text = opened_file.read()
    ...
else:  
    opened_file.close()
Python siempre se asegura de que elsese ejecute el código en el bloque, independientemente de cualquier cosa que pueda suceder. Esta es la forma en que los programadores en otros lenguajes manejan la administración de recursos, pero los programadores de Python obtienen un mecanismo especial que les permite implementar la misma funcionalidad sin toda la plantilla. Aquí es donde entran en juego los gestores de contexto.

Implementación de gestores de contexto

Ahora que hemos terminado con la parte más importante para comprender a los gestores de contexto, podemos comenzar a implementarlos. Para este tutorial, implementaremos una Fileclase personalizada Es totalmente redundante ya que Python ya proporciona esto, pero no obstante, será un buen ejercicio de aprendizaje, ya que siempre podremos relacionarnos con la Fileclase que ya existe en la biblioteca estándar.
La forma estándar y de "nivel inferior" de implementar un administrador de contexto es definir dos métodos "mágicos" en la clase para la que desea implementar la administración de recursos, __enter____exit__Si te estás perdiendo, pensando, "¿qué es esta cosa del método mágico? Nunca he oído hablar de esto antes", bueno, si has comenzado a hacer programación orientada a objetos en Python, seguramente ya has encontrado un método mágico, el método __init__.
A falta de mejores palabras, son métodos especiales que puedes definir para hacer que tus clases sean más inteligentes o agregarles "magia". Puede encontrar una buena lista de referencias de todos los métodos mágicos disponibles en Python aquí .
De todos modos, volviendo al tema, antes de comenzar a implementar estos dos métodos mágicos, tendremos que entender su propósito. __enter__es el método al que se llama cuando abrimos el recurso, o para ponerlo de una manera un poco más técnica, cuando "ingresamos" en el contexto de tiempo de ejecución . La withdeclaración vinculará el valor de retorno de este método al objetivo especificado en la ascláusula de la declaración.
Veamos un ejemplo:
class FileManager:  
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.opened_file = open(self.filename)
        return self.opened_file
Como puede ver, el __enter__método es abrir el recurso (el archivo) y devolverlo. Cuando usamos esto FileManageren una withdeclaración, este método se llamará y su valor de retorno se vinculará a la variable de destino que mencionó en la ascláusula. He demostrado en el siguiente fragmento de código:
with FileManager('readme.txt') as file:  
    text = file.read()
Vamos a desglosarlo parte por parte. En primer lugar, FileManagerse crea una instancia de la clase cuando la creamos, pasando el nombre de archivo "readme.txt" al constructor. Luego, la withdeclaración comienza a trabajar en ella: llama al __enter__método de ese FileManagerobjeto y asigna el valor devuelto a la filevariable mencionada en la ascláusula. Luego, dentro del withbloque, podemos hacer lo que queramos hacer con el recurso abierto.
La otra parte importante del rompecabezas es el __exit__método. El __exit__método contiene un código de limpieza que debe ejecutarse después de que hayamos terminado con el recurso, sin importar qué. Las instrucciones en este método serán similares a las del elsebloque que discutimos anteriormente al discutir el manejo de excepciones. Para reiterar, el __exit__método contiene instrucciones para cerrar correctamente el manejador de recursos, de modo que el recurso se libere para que otros programas en el sistema operativo lo sigan utilizando.
Ahora veamos cómo podemos escribir este método:
class FileManager:  
    def __exit__(self. *exc):
        self.opened_file.close()
Ahora, cada vez que se usen las instancias de esta clase en una withdeclaración, __exit__se llamará a este método antes de que el programa salga del withbloque, o antes de que el programa se detenga debido a alguna excepción. Ahora veamos a toda la FileManagerclase para que tengamos una idea completa.
class FileManager:  
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.opened_file = open(self.filename)
        return self.opened_file

    def __exit__(self, *exc):
        self.opened_file.close()
Bastante simple, ¿verdad? Acabamos de definir las acciones de apertura y limpieza en los métodos mágicos respectivos, y Python se hará cargo de la administración de recursos donde sea que se use esta clase. Eso me lleva al siguiente tema, las diferentes maneras en que podemos usar las clases del administrador de contexto, como esta FileManagerclase.

Uso de gestores de contexto

No hay mucho que explicar aquí, así que en lugar de escribir párrafos largos, le proporcionaré algunos fragmentos de código en esta sección:
file = FileManager('readme.txt')  
with file as managed_file:  
    text = managed_file.read()
    print(text)
with FileManager('readme.txt') as managed_file:  
    text = managed_file.read()
    print(text)
def open_file(filename):  
    file = FileManager(filename)
    return file

with open_file('readme.txt') as managed_file:  
    text = managed_file.read()
    print(text)
Puedes ver que la clave para recordar es,
  1. El objeto pasado a la withdeclaración debe tener __enter____exit__métodos.
  2. El __enter__método debe devolver el recurso que se va a utilizar en el withbloque.
Importante : hay algunas sutilezas que omití para que la discusión sea al punto. Para conocer las especificaciones exactas de estos métodos mágicos, consulte la documentación de Python aquí .

Usando contextlib

El principio guía de Zen of Python —Python como una lista de aforismos — declara que
Lo simple es mejor que lo complejo.
Para realmente llevar este punto a casa, los desarrolladores de Python han creado una biblioteca llamada contextlib que contiene utilidades relacionadas con los administradores de contexto, como si no hubieran simplificado suficientemente el problema de la administración de recursos. Aquí voy a mostrar solo uno de ellos brevemente, te recomiendo que consultes los documentos oficiales de Python para obtener más información.
from contextlib import contextmanager

@contextmanager
def open_file(filename):  
    opened_file = open(filename)
    try:
        yield opened_file
    finally:
        opened_file.close()
Al igual que el código anterior, simplemente podemos definir una función que yieldes el recurso protegido en una trydeclaración, cerrándola en la finallydeclaración posterior Otra forma de entenderlo:
  • Todo el contenido que de otro modo pondría en el __enter__método, excepto la returndeclaración, va antes del trybloque aquí, básicamente las instrucciones para abrir el recurso.
  • En lugar de devolver el recurso, usted yield, dentro de un trybloque.
  • El contenido del __exit__método va dentro del finallybloque correspondiente .
Una vez que tengamos esa función, podemos decorarla usando el contextlib.contextmanagerdecorador y estamos bien.
with open_file('readme.txt') as managed_file:  
    text = managed_file.read()
    print(text)
Como puede ver, la open_filefunción decorada devuelve un administrador de contexto y podemos usarlo directamente. Esto nos permite lograr el mismo efecto que al crear la FileManagerclase, sin toda la molestia.

Otras lecturas

Si te sientes entusiasta y quieres leer más sobre los administradores de contexto, te animo a que visites los siguientes enlaces:

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

outbrain

Páginas