statement - with python español
¿Para qué está diseñada la declaración “con” de python? (10)
Me encontré con el Python with
declaración por primera vez hoy. ¡He estado usando Python a la ligera durante varios meses y ni siquiera sabía de su existencia! Dado su estado un tanto oscuro, pensé que valdría la pena preguntar:
- ¿Para qué se utiliza Python
with
declaración? - Para que lo usas?
- ¿Debo tener en cuenta algún problema, o anti-patrones comunes asociados con su uso? Cualquier caso en el que sea mejor usarlo
try..finally
quewith
? - ¿Por qué no se usa más ampliamente?
- ¿Qué clases de biblioteca estándar son compatibles con él?
Creo que otros usuarios ya han respondido esto antes que yo, así que solo lo agrego para completar: la instrucción
with
simplifica el manejo de excepciones al resumir las tareas comunes de preparación y limpieza en los llamados administradores de contexto . Más detalles se pueden encontrar en PEP 343 . Por ejemplo, la declaraciónopen
es un administrador de contexto en sí mismo, que le permite abrir un archivo, mantenerlo abierto mientras la ejecución esté en el contexto de la instrucciónwith
donde lo usó, y cerrarlo tan pronto como deje la contexto, no importa si lo ha dejado debido a una excepción o durante el flujo de control regular. Por lo tanto, la instrucciónwith
se puede usar de manera similar al patrón RAII en C ++: la instrucciónwith
adquiere algunos recursos y se libera cuando se deja el contextowith
.Algunos ejemplos son: abrir archivos
with open(filename) as fp:
adquirir bloqueoswith lock:
(donde ellock
es una instancia dethreading.Lock
). También puede construir sus propios gestores de contexto utilizando el decoradorcontextlib
desdecontextlib
. Por ejemplo, a menudo uso esto cuando tengo que cambiar el directorio actual temporalmente y luego regresar a donde estaba:from contextlib import contextmanager import os @contextmanager def working_directory(path): current_dir = os.getcwd() os.chdir(path) try: yield finally: os.chdir(current_dir) with working_directory("data/stuff"): # do something within data/stuff # here I am back again in the original working directory
Aquí hay otro ejemplo que redirige temporalmente
sys.stdin
,sys.stdout
ysys.stderr
a algún otro manejador de archivos y los restaura más tarde:from contextlib import contextmanager import sys @contextmanager def redirected(**kwds): stream_names = ["stdin", "stdout", "stderr"] old_streams = {} try: for sname in stream_names: stream = kwds.get(sname, None) if stream is not None and stream != getattr(sys, sname): old_streams[sname] = getattr(sys, sname) setattr(sys, sname, stream) yield finally: for sname, stream in old_streams.iteritems(): setattr(sys, sname, stream) with redirected(stdout=open("/tmp/log.txt", "w")): # these print statements will go to /tmp/log.txt print "Test entry 1" print "Test entry 2" # back to the normal stdout print "Back to normal stdout again"
Y finalmente, otro ejemplo que crea una carpeta temporal y la limpia al salir del contexto:
from tempfile import mkdtemp from shutil import rmtree @contextmanager def temporary_dir(*args, **kwds): name = mkdtemp(*args, **kwds) try: yield name finally: shutil.rmtree(name) with temporary_dir() as dirname: # do whatever you want
En Python, generalmente, la declaración " with " se usa para abrir un archivo, procesar los datos presentes en el archivo y también para cerrar el archivo sin llamar al método close (). La declaración “with” hace que el manejo de excepciones sea más sencillo al proporcionar actividades de limpieza.
Forma general de con:
with open(“file name”, “mode”) as file-var:
processing statements
nota: no es necesario cerrar el archivo llamando a close () al archivo-var.close ()
La declaración with funciona con los llamados gestores de contexto:
http://docs.python.org/release/2.5.2/lib/typecontextmanager.html
La idea es simplificar el manejo de excepciones haciendo la limpieza necesaria después de dejar el bloque ''con''. Algunas de las incorporaciones de Python ya funcionan como gestores de contexto.
Los puntos 1, 2 y 3 están razonablemente bien cubiertos:
4: es relativamente nuevo, solo está disponible en python2.6 + (o python2.5 usando from __future__ import with_statement
)
Nuevamente, para completar, agregaré mi caso de uso más útil para las declaraciones.
Hago mucha computación científica y para algunas actividades necesito la biblioteca Decimal
para cálculos de precisión arbitrarios. Parte de mi código necesito alta precisión y para la mayoría de las otras partes necesito menos precisión.
Configuré mi precisión predeterminada en un número bajo y luego uso with
para obtener una respuesta más precisa para algunas secciones:
from decimal import localcontext
with localcontext() as ctx:
ctx.prec = 42 # Perform a high precision calculation
s = calculate_something()
s = +s # Round the final result back to the default precision
Lo uso mucho con la prueba hipergeométrica que requiere la división de grandes números como resultado de los materiales factoriales. Cuando realice cálculos de escala genómica, debe tener cuidado con los errores de redondeo y desbordamiento.
Otro ejemplo de soporte listo para usar, y uno que puede ser un poco desconcertante al principio cuando está acostumbrado a la forma en que se comporta open()
, son los objetos de connection
de los módulos de bases de datos más populares, como:
Los objetos de connection
son administradores de contexto y, como tales, se pueden utilizar de forma inmediata en una with-statement
, sin embargo, cuando se usa lo anterior, tenga en cuenta que:
Cuando se termina
with-block
, ya sea con una excepción o sin ella, la conexión no se cierra . En caso de que elwith-block
con finalice con una excepción, la transacción se revierte, de lo contrario, la transacción se compromete.
Esto significa que el programador debe tener cuidado de cerrar la conexión por sí mismo, pero permite adquirir una conexión y usarla en varias with-statements
, como se muestra en los psycopg2 :
conn = psycopg2.connect(DSN)
with conn:
with conn.cursor() as curs:
curs.execute(SQL1)
with conn:
with conn.cursor() as curs:
curs.execute(SQL2)
conn.close()
En el ejemplo anterior, observará que los objetos del cursor
de psycopg2
también son administradores de contexto. De la documentación relevante sobre el comportamiento:
Cuando un
cursor
sale delwith-block
, se cierra, liberando cualquier recurso eventualmente asociado con él. El estado de la transacción no se ve afectado.
Python with
statement es un soporte de lenguaje incorporado del lenguaje de Resource Acquisition Is Initialization
comúnmente utilizado en C ++. Está destinado a permitir la adquisición y liberación segura de recursos del sistema operativo.
La instrucción with
crea recursos dentro de un ámbito / bloque. Usted escribe su código usando los recursos dentro del bloque. Cuando el bloque sale, los recursos se liberan limpiamente independientemente del resultado del código en el bloque (es decir, si el bloque sale normalmente o debido a una excepción).
Muchos recursos en la biblioteca de Python que obedecen el protocolo requerido por la declaración with
y, por lo tanto, se pueden utilizar de manera inmediata. Sin embargo, cualquiera puede hacer recursos que se pueden usar en una declaración con la implementación del protocolo bien documentado: PEP 0343
Úselo siempre que adquiera recursos en su aplicación que se deban renunciar explícitamente, como archivos, conexiones de red, bloqueos y similares.
Sugeriría dos conferencias interesantes:
1. La instrucción with
se usa para envolver la ejecución de un bloque con métodos definidos por un administrador de contexto. Esto permite un try...except...finally
común try...except...finally
los patrones de uso se encapsulan para una reutilización conveniente.
2. Podrías hacer algo como:
with open("foo.txt") as foo_file:
data = foo_file.read()
O
from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
do_something()
O (Python 3.1)
with open(''data'') as input_file, open(''result'', ''w'') as output_file:
for line in input_file:
output_file.write(parse(line))
O
lock = threading.Lock()
with lock:
# Critical section of code
3. No veo ninguna Antipattern aquí.
Citando Dive into Python :
Intenta ... por fin es bueno. con es mejor
4. Supongo que está relacionado con el hábito de los programadores de usar la declaración try..catch..finally
de otros lenguajes.
Un ejemplo de un antipattern podría ser usar with
dentro de un bucle cuando sería más eficiente tener el with
fuera del bucle
por ejemplo
for row in lines:
with open("outfile","a") as f:
f.write(row)
vs
with open("outfile","a") as f:
for row in lines:
f.write(row)
La primera forma es abrir y cerrar el archivo para cada row
que puede causar problemas de rendimiento en comparación con la segunda manera, ya que abre y cierra el archivo una sola vez.
Ver PEP 343 - La declaración ''con'' , hay una sección de ejemplo al final.
... nueva declaración "con" en el lenguaje Python para que sea posible eliminar los usos estándar de las declaraciones try / finally.