Usando la declaración "con" de Python con el bloque try-except

96

¿Es esta la forma correcta de usar la declaración de python "con" en combinación con un bloque try-except ?:

try:
    with open("file", "r") as f:
        line = f.readline()
except IOError:
    <whatever>

Si es así, entonces considerando la antigua forma de hacer las cosas:

try:
    f = open("file", "r")
    line = f.readline()
except IOError:
    <whatever>
finally:
    f.close()

¿El principal beneficio de la declaración "con" aquí es que podemos deshacernos de tres líneas de código? No me parece tan convincente para este caso de uso (aunque entiendo que la declaración "with" tiene otros usos).

EDITAR: ¿Es idéntica la funcionalidad de los dos bloques de código anteriores?

EDIT2: Las primeras respuestas hablan en general sobre los beneficios de usar "con", pero esos parecen tener un beneficio marginal aquí. Todos hemos estado (o deberíamos haber estado) llamando explícitamente a f.close () durante años. Supongo que un beneficio es que los codificadores descuidados se beneficiarán de usar "con".

gaefan
fuente
Para mí, no tener que recordar cerrar () las cosas en una declaración final es una razón suficientemente buena para usar 'con'. He visto una gran cantidad de código que no cierra sus recursos. Y 'con' no tiene inconvenientes por lo que puedo ver.
Raúl Salinas-Monteagudo

Respuestas:

139
  1. Los dos bloques de código que proporcionó no son equivalentes
  2. El código que describió como una forma antigua de hacer las cosas tiene un error grave: en caso de que la apertura del archivo falle, obtendrá una segunda excepción en la finallycláusula porque fno está vinculada.

El código de estilo antiguo equivalente sería:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

Como puede ver, la withdeclaración puede hacer que las cosas sean menos propensas a errores. En las versiones más recientes de Python (2.7, 3.1), también puede combinar varias expresiones en una withdeclaración. Por ejemplo:

with open("input", "r") as inp, open("output", "w") as out:
    out.write(inp.read())

Además de eso, personalmente considero una mala costumbre detectar cualquier excepción lo antes posible. Este no es el propósito de las excepciones. Si la función IO que puede fallar es parte de una operación más complicada, en la mayoría de los casos el IOError debe abortar toda la operación y, por lo tanto, manejarse en un nivel externo. Usando withdeclaraciones, puede deshacerse de todas estas try...finallydeclaraciones en niveles internos.

Bernd Petersohn
fuente
7

Si el contenido del finallybloque está determinado por las propiedades del objeto de archivo que se está abriendo, ¿por qué no debería ser el implementador del objeto de archivo quien escriba el finallybloque? Ese es el beneficio de la withdeclaración, mucho más que ahorrarle tres líneas de código en esta instancia en particular.

Y sí, la forma en que ha combinado withy try-exceptes prácticamente la única forma de hacerlo, ya que los errores excepcionales causados ​​dentro de la opendeclaración en sí no se pueden detectar dentro del withbloque.

Peter Milley
fuente
1

Creo que te equivocaste con la declaración "con" de que solo reduce las líneas. Realmente realiza la inicialización y maneja el desmontaje.

En tu caso "con" hace

  • abre un archivo,
  • procesar su contenido, y
  • asegúrese de cerrarlo.

Aquí hay un enlace para entender la declaración "con": http://effbot.org/zone/python-with-statement.htm

Editar: Sí, su uso de "con" es correcto y la funcionalidad de ambos bloques de código es idéntica. Pregunta sobre por qué usar "con"? es por los beneficios que obtiene con él. como mencionaste sobre la pérdida accidental de f.close ().

YoK
fuente
-4

La forma más Pythonic para los siguientes códigos es:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

try:
    f = open("file", "r")
except IOError:
    <whatever>
else:
    f.close()
Leo Liu
fuente
1
He agregado formato de código para ti; facilita la lectura. Pero es posible que desee volver a verificar para asegurarse de que no he roto la sangría.
andrewsi
2
No, su versión no hace lo mismo que el código original. Incluso si agrega la readline()llamada que falta , su versión no cierra el archivo si el readline()resultado es un IOError.
Aleksi Torhamo