En tiempos prehistóricos (Python 1.4) hicimos:
fp = open('filename.txt')
while 1:
line = fp.readline()
if not line:
break
print line
después de Python 2.1, hicimos:
for line in open('filename.txt').xreadlines():
print line
antes de obtener el protocolo iterador conveniente en Python 2.3, y podríamos hacer:
for line in open('filename.txt'):
print line
He visto algunos ejemplos usando el más detallado:
with open('filename.txt') as fp:
for line in fp:
print line
¿Es este el método preferido para avanzar?
[editar] Entiendo que la instrucción with asegura el cierre del archivo ... pero ¿por qué no se incluye eso en el protocolo iterador para los objetos de archivo?
python
python-3.x
python-2.7
thebjorn
fuente
fuente
Respuestas:
Hay exactamente una razón por la cual se prefiere lo siguiente:
Todos estamos mimados por el esquema de conteo de referencias relativamente determinista de CPython para la recolección de basura. Otras implementaciones hipotéticas de Python no cerrarán necesariamente el archivo "lo suficientemente rápido" sin el
with
bloque si usan algún otro esquema para recuperar memoria.En tal implementación, es posible que obtenga un error de "demasiados archivos abiertos" del sistema operativo si su código abre los archivos más rápido de lo que el recolector de basura llama a los finalizadores en los controladores de archivos huérfanos. La solución habitual es activar el GC de inmediato, pero este es un truco desagradable y debe ser realizado por cada función que pueda encontrar el error, incluidas las de las bibliotecas. Qué pesadilla.
O simplemente podrías usar el
with
bloque.Pregunta extra
(Deje de leer ahora si solo le interesan los aspectos objetivos de la pregunta).
Esta es una pregunta subjetiva sobre el diseño de API, por lo que tengo una respuesta subjetiva en dos partes.
A nivel intestinal, esto se siente mal, porque hace que el protocolo iterador haga dos cosas separadas: iterar sobre líneas y cerrar el identificador de archivo, y a menudo es una mala idea hacer que una función de aspecto simple realice dos acciones. En este caso, se siente especialmente mal porque los iteradores se relacionan de una manera cuasifuncional y basada en valores con el contenido de un archivo, pero administrar los identificadores de archivos es una tarea completamente separada. Aplastar ambos, invisiblemente, en una sola acción, es sorprendente para los humanos que leen el código y hace que sea más difícil razonar sobre el comportamiento del programa.
Otros idiomas han llegado esencialmente a la misma conclusión. Haskell coqueteó brevemente con el llamado "IO diferido" que le permite iterar sobre un archivo y cerrarlo automáticamente cuando llega al final de la transmisión, pero en la actualidad se desaconseja usar IO diferido en Haskell, y Haskell los usuarios se han movido principalmente a una administración de recursos más explícita como Conduit, que se comporta más como el
with
bloque en Python.A nivel técnico, hay algunas cosas que puede hacer con un identificador de archivo en Python que no funcionarían tan bien si la iteración cerrara el identificador de archivo. Por ejemplo, supongamos que necesito iterar sobre el archivo dos veces:
Si bien este es un caso de uso menos común, considere el hecho de que podría haber agregado las tres líneas de código en la parte inferior a una base de código existente que originalmente tenía las tres líneas superiores. Si la iteración cerrara el archivo, no podría hacerlo. Por lo tanto, mantener la iteración y la administración de recursos separadas hace que sea más fácil componer fragmentos de código en un programa Python más grande y funcional.
La capacidad de composición es una de las características de usabilidad más importantes de un lenguaje o API.
fuente
with
sin embargo, te da tranquilidad, por lo que sigue siendo una buena práctica.Si,
es el camino a seguir
No es más detallado. Es mas seguro.
fuente
si la línea adicional lo apaga, puede usar una función de envoltura como esta:
en Python 3.3, la
yield from
declaración haría esto aún más corto:fuente
fuente