with
La declaración en Python se usa en el manejo de excepciones para hacer que el código sea más limpio y mucho más legible. Simplifica la gestión de recursos comunes como flujos de archivos. Observe el siguiente ejemplo de código sobre cómo el uso de la with
declaración hace que el código sea más limpio.
# file handling # 1) without using with statement file = open('file_path', 'w') file.write('hello world !') file.close() # 2) without using with statement file = open('file_path', 'w') try: file.write('hello world') finally: file.close()
# using with statement with open('file_path', 'w') as file: file.write('hello world !')
Tenga en cuenta que, a diferencia de las dos primeras implementaciones, no es necesario llamar file.close()
cuando se usa la with
instrucción. La with
declaración en sí misma garantiza la adquisición y liberación adecuadas de recursos. Una excepción durante la file.write()
llamada en la primera implementación puede evitar que el archivo se cierre correctamente, lo que puede introducir varios errores en el código, es decir, muchos cambios en los archivos no entran en vigencia hasta que el archivo se cierra correctamente.
El segundo enfoque del ejemplo anterior se ocupa de todas las excepciones, pero el uso de la with
declaración hace que el código sea compacto y mucho más legible. Por lo tanto, with
la declaración ayuda a evitar errores y fugas al garantizar que un recurso se libere correctamente cuando el código que usa el recurso se ejecute por completo. La with
declaración se usa popularmente con flujos de archivos, como se muestra arriba y con bloqueos, sockets, subprocesos y telnets, etc.
Compatibilidad con la declaración «with» en objetos definidos por el usuario
No hay nada especial open()
que lo haga utilizable con la with
declaración y se puede proporcionar la misma funcionalidad en los objetos definidos por el usuario. La declaración de respaldo with
en sus objetos asegurará que nunca deje ningún recurso abierto.
Para usar with
la declaración en objetos definidos por el usuario, solo necesita agregar los métodos __enter__()
y __exit__()
en los métodos del objeto. Considere el siguiente ejemplo para mayor aclaración.
# a simple file writer object class MessageWriter(object): def __init__(self, file_name): self.file_name = file_name def __enter__(self): self.file = open(self.file_name, 'w') return self.file def __exit__(self): self.file.close() # using with statement with MessageWriter with MessageWriter('my_file.txt') as xfile: xfile.write('hello world')
Examinemos el código anterior. Si te fijas, lo que sigue a la with
palabra clave es el constructor de MessageWriter
. Tan pronto como la ejecución ingresa al contexto de la with
declaración, MessageWriter
se crea un objeto y Python llama al __enter__()
método. En este __enter__()
método, inicialice el recurso que desea usar en el objeto. Este __enter__()
método siempre debe devolver un descriptor del recurso adquirido.
¿Qué son los descriptores de recursos?
Estos son los identificadores proporcionados por el sistema operativo para acceder a los recursos solicitados. En el siguiente bloque de código, file
hay un descriptor del recurso de flujo de archivos.
file = open('hello.txt')
En el MessageWriter
ejemplo anterior, el __enter__()
método crea un descriptor de archivo y lo devuelve. El nombre xfile
aquí se usa para referirse al descriptor de archivo devuelto por el __enter__()
método. El bloque de código que utiliza el recurso adquirido se coloca dentro del bloque de la with
instrucción. Tan pronto como with
se ejecuta el código dentro del bloque, __exit__()
se llama al método. Todos los recursos adquiridos se liberan en el __exit__()
método. Así es como usamos la with
declaración con objetos definidos por el usuario.
Esta interfaz de __enter__()
métodos __exit__()
que proporciona el soporte de with
declaraciones en objetos definidos por el usuario se denomina Administrador de contexto .
El módulo contextlib
Un administrador de contexto basado en clases, como se muestra arriba, no es la única forma de admitir la with
declaración en objetos definidos por el usuario. El contextlib
módulo proporciona algunas abstracciones más basadas en la interfaz básica del administrador de contexto. Así es como podemos reescribir el administrador de contexto para el MessageWriter
objeto usando el contextlib
módulo.
from contextlib import contextmanager class MessageWriter(object): def __init__(self, filename): self.file_name = filename @contextmanager def open_file(self): try: file = open(self.file_name, 'w') yield file finally: file.close() # usage message_writer = MessageWriter('hello.txt') with message_writer.open_file() as my_file: my_file.write('hello world')
En este ejemplo de código, debido a la yield
declaración en su definición, la función open_file()
es una función generadora .
Cuando se llama a esta open_file()
función, crea un descriptor de recursos llamado file
. Este descriptor de recursos luego se pasa a la persona que llama y está representado aquí por la variable my_file
. Después de ejecutar el código dentro del with
bloque, el control del programa vuelve a la open_file()
función. La open_file()
función reanuda su ejecución y ejecuta el código que sigue a la yield
declaración. Esta parte del código que aparece después de la yield
declaración libera los recursos adquiridos. El @contextmanager
aquí es un decorador .
La implementación anterior basada en clases y esta implementación basada en generadores de administradores de contexto es internamente la misma. Si bien el último parece más legible, requiere el conocimiento de generadores, decoradores y yield
.
Publicación traducida automáticamente
Artículo escrito por Manthanchauhan y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA