¿Forma correcta de escribir línea en archivo?

1069

Estoy acostumbrado a hacer print >>f, "hi there"

Sin embargo, parece que print >>está en desuso. ¿Cuál es la forma recomendada de hacer la línea de arriba?

Actualización : Respecto a todas esas respuestas con "\n"... ¿es universal o específico de Unix? IE, ¿debería estar haciendo "\r\n"en Windows?

Yaroslav Bulatov
fuente
11
"\ n" no es específico de Unix. Cuando el archivo se abre en modo de texto (predeterminado), se traduce automáticamente a la línea correcta que finaliza para la plataforma actual. Escribir "\ r \ n" produciría "\ r \ r \ n", lo cual está mal.
D Coetzee
Simplemente agregue la instrucción print ord (os.linesep) para ver el código ascii (10 en la mayoría de los sistemas UNIX)
Stefan Gruenwald
¿Por qué crees que está en desuso?
xxx ---

Respuestas:

1153

Esto debería ser tan simple como:

with open('somefile.txt', 'a') as the_file:
    the_file.write('Hello\n')

De la documentación:

No lo use os.linesepcomo terminador de línea cuando escriba archivos abiertos en modo texto (el valor predeterminado); use un solo '\ n' en su lugar, en todas las plataformas.

Algunas lecturas útiles:

Johnsyweb
fuente
37
Este ejemplo es mejor que el ejemplo de abrir / cerrar. Usar withes una forma más segura de recordar cerrar un archivo.
Eyal
18
No tengo que llamar the_file.close()?
Hussain
19
no, no lo haces: stackoverflow.com/questions/3012488/…
Tal Jerome
@Johnsyweb ¿Por qué dices "os.linesep. Hay muchas cosas buenas en os!", Cuando anteriormente en la publicación te recomendó no usarlo? Sospecho que hay una edición aquí, y podría ser la razón de los votos negativos.
Horse SMith
1
@ user3226167: Ese es un punto interesante. Pero, ¿por qué abrirías un archivo binario para escribir texto sin formato?
Johnsyweb
961

Debe usar la print()función que está disponible desde Python 2.6+

from __future__ import print_function  # Only needed for Python 2
print("hi there", file=f)

Para Python 3 no necesita import, ya que la print()función es la predeterminada.

La alternativa sería usar:

f = open('myfile', 'w')
f.write('hi there\n')  # python will convert \n to os.linesep
f.close()  # you can omit in most cases as the destructor will call it

Citando de la documentación de Python sobre nuevas líneas:

En la salida, si es de nueva línea Ninguno, ningún '\n'caracteres escritos se convierten a la línea de separación por defecto del sistema, os.linesep. Si la nueva línea es '', no se realiza ninguna traducción. Si la nueva línea es cualquiera de los otros valores legales, los '\n'caracteres escritos se traducen a la cadena dada.

Sorin
fuente
35
-1 "Si quiere estar seguro, agregue os.linesep a la cadena en lugar de \n" require newline = "", de lo contrario obtendría \r\r\nen Windows. No hay ninguna razón para perder el tiempo con os.linesep.
John Machin
77
@Sorin: Su edición para agregar el modo de escritura es, por supuesto, una mejora. Sin embargo, extrañamente permanece intransigente sobre os.linesep. Mira mi respuesta. Por cierto, la documentación que cita es para 3.x, pero esta parte también es válida para 2.x en modo de texto: cualquier carácter '\ n' escrito se traduce al separador de línea predeterminado del sistema, os.linesep * . .. Windows: escribir os.linesep es lo mismo que escribir \r\nque contiene el \nque se traduce a os.linesep, que es \r\nel resultado final \r\r\n.
John Machin
77
@ John tenías razón, corregí el error os.linesep. Gracias.
Sorin
3
Para anexar ¿no es cierto open('myfile','a')en su lugar open('myfile','w')?
NeDark
66
@BradRuderman Eso es parte del estándar POSIX para lo que constituye una "línea" en un archivo de texto, es decir, cada línea en un archivo de texto debe terminar con una nueva línea, incluso la última línea.
Wheeler
116

Los documentos de Python recomiendan de esta manera:

with open('file_to_write', 'w') as f:
    f.write('file contents\n')

Entonces esta es la forma en que generalmente lo hago :)

Declaración de docs.python.org :

Es una buena práctica usar la palabra clave 'con' cuando se trata de objetos de archivo. Esto tiene la ventaja de que el archivo se cierra correctamente después de que finaliza su suite, incluso si se genera una excepción en el camino. También es mucho más corto que escribir bloques equivalentes try-finally.

j7nn7k
fuente
1
No me gusta así cuando necesito anidar el withinterior de un bucle. Eso me hace abrir y cerrar constantemente el archivo a medida que avanzo en mi ciclo. ¿Quizás me estoy perdiendo algo aquí, o esto es realmente una desventaja en este escenario particular?
Sibbs Gambling
38
¿Qué hay de bucle dentro de la con?
j7nn7k
@ j7nn7k para línea en fd:
momstouch
86

En cuanto a os.linesep:

Aquí hay una sesión de intérprete Python 2.7.1 exacta sin editar en Windows:

Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.linesep
'\r\n'
>>> f = open('myfile','w')
>>> f.write('hi there\n')
>>> f.write('hi there' + os.linesep) # same result as previous line ?????????
>>> f.close()
>>> open('myfile', 'rb').read()
'hi there\r\nhi there\r\r\n'
>>>

En Windows:

Como se esperaba, os.linesep NO produce el mismo resultado que '\n'. No hay forma de que pueda producir el mismo resultado. 'hi there' + os.linesepes equivalente a 'hi there\r\n', que NO es equivalente a 'hi there\n'.

Es así de simple: uso \nque se traducirá automáticamente a os.linesep. Y ha sido así de simple desde el primer puerto de Python a Windows.

No tiene sentido usar os.linesep en sistemas que no son de Windows, y produce resultados incorrectos en Windows.

¡NO USE os.linesep!

John Machin
fuente
gran ejemplo: ¿tienes curiosidad si eres un usuario de ipython? buenas funciones para formatear sesiones
Alvin
No estoy completamente seguro de lo que intenta decirnos aquí. os.linesep devolverá el carácter de término de línea (o cadena) según lo definido por el sistema operativo. Windows usa \ r \ n para finales de línea de forma predeterminada. Sin embargo, se reconoce un solo \ n. Usar \ n dará una SALIDA totalmente portátil, pero os.linesep no está mal en Windows.
Gusdor
55
@Gusdor: El punto es que si usa explícitamente os.linesepen Windows en modo de texto, el resultado es el \r\r\nque está mal. "Windows usa ..." no tiene sentido. La biblioteca de tiempo de ejecución C (y por tanto Python) traducir \na \r\nen la salida en modo texto. Otro software puede comportarse de manera diferente. NO es el caso de que todo el software que se ejecuta en Windows reconozca un solitario \ncomo separador de línea cuando se lee en modo texto. Python lo hace. El editor de texto del Bloc de notas de Microsoft no.
John Machin
66
Podría decirse que alguien más lo leerá, no tú, con un software de mickey-mouse que se burlará del extra \r...
John Machin
2
@Gusdor, vienes a Python desde un idioma diferente, donde usar '\ n' da como resultado la salida de '\ n' en la ventana, en lugar de '\ r \ n', por lo que carece del '\ r' esperado por tonto editores de texto? Como dice John, no es así como se comporta Python: '\ n' se reemplaza automáticamente por '\ r \ n', si eso es lo que os.linesep dice que haga. Por lo tanto, decir explícitamente os.linesep es "incorrecto" aquí. Es como Department of Redundancy Department. Sí, tú puedes hacerlo. No, no quieres hacerlo.
ToolmakerSteve
55

No creo que haya una forma "correcta".

Yo usaría:

with open ('myfile', 'a') as f: f.write ('hi there\n')

En memoria de Tim Toady .

Hiperbóreo
fuente
Pero el OP podría querer escribir cosas adicionales en el archivo. Aquí el archivo se cerrará cuando withsalga del alcance.
Keith
Eso podría querer ser open(..., 'a')o incluso 'at'.
mtrw
55
Erm, si. Esa es la idea de usar con. Si desea mantener abierto el archivo, simplemente abra abierto al principio y cierre cuando haya terminado ...
Hyperboreus
1
@mtrw. Cierto. OP estaba anexando.
Hyperboreus
1
En lo que respecta a Python, RIP Tim Toady, y muy, muy legítimamente
Mr_and_Mrs_D
21

En Python 3 es una función, pero en Python 2 puede agregar esto al principio del archivo fuente:

from __future__ import print_function

Entonces lo haces

print("hi there", file=f)
Keith
fuente
17

Si está escribiendo una gran cantidad de datos y la velocidad es una preocupación que probablemente debería seguir f.write(...). Hice una comparación de velocidad rápida y fue considerablemente más rápido que print(..., file=f)cuando realizaba una gran cantidad de escrituras.

import time    

start = start = time.time()
with open("test.txt", 'w') as f:
    for i in range(10000000):
        # print('This is a speed test', file=f)
        # f.write('This is a speed test\n')
end = time.time()
print(end - start)

En promedio, writeterminé en 2.45s en mi máquina, mientras que printtardó aproximadamente 4 veces más (9.76s). Dicho esto, en la mayoría de los escenarios del mundo real, esto no será un problema.

Si elige ir print(..., file=f), probablemente encontrará que querrá suprimir la nueva línea de vez en cuando, o reemplazarla por otra cosa. Esto puede hacerse configurando el endparámetro opcional , por ejemplo;

with open("test", 'w') as f:
    print('Foo1,', file=f, end='')
    print('Foo2,', file=f, end='')
    print('Foo3', file=f)

De cualquier forma que elija, le sugiero que use, withya que hace que el código sea mucho más fácil de leer.

Actualización : esta diferencia en el rendimiento se explica por el hecho de que writeestá altamente protegida y regresa antes de que se realicen las escrituras en el disco (vea esta respuesta ), mientras que print(probablemente) usa el almacenamiento en línea de la memoria intermedia. Una prueba simple para esto sería verificar el rendimiento de escrituras largas también, donde las desventajas (en términos de velocidad) para el almacenamiento en línea serían menos pronunciadas.

start = start = time.time()
long_line = 'This is a speed test' * 100
with open("test.txt", 'w') as f:
    for i in range(1000000):
        # print(long_line, file=f)
        # f.write(long_line + '\n')
end = time.time()

print(end - start, "s")

La diferencia de rendimiento ahora se vuelve mucho menos pronunciada, con un tiempo promedio de 2.20s para writey 3.10s para print. Si necesita concatenar un montón de cadenas para obtener este rendimiento de línea tan largo, sufrirá, por lo que los casos de uso donde printserían más eficientes son un poco raros.

Robin Keskisarkka
fuente
10

Desde 3.5 también puede usar el pathlibpara ese propósito:

Path.write_text(data, encoding=None, errors=None)

Abra el archivo apuntado en modo texto, escriba datos en él y cierre el archivo:

import pathlib

pathlib.Path('textfile.txt').write_text('content')
johnson
fuente
5

Cuando dijo Línea, significa algunos caracteres serializados que terminan en '\ n' caracteres. La línea debe ser la última en algún punto, por lo que debemos considerar '\ n' al final de cada línea. Aquí hay solución:

with open('YOURFILE.txt', 'a') as the_file:
    the_file.write("Hello")

en el modo de agregar después de cada escritura, el cursor se mueve a una nueva línea, si desea usar el wmodo, debe agregar \ncaracteres al final de la write()función:

the_file.write("Hello\n")
Reza Tanzifi
fuente
1
"en modo de adición después de cada escritura, el cursor se mueve a una nueva línea" - no, no lo es.
Un
3

También se puede usar el iomódulo como en:

import io
my_string = "hi there"

with io.open("output_file.txt", mode='w', encoding='utf-8') as f:
    f.write(my_string)
kmario23
fuente
1

Para escribir texto en un archivo en el matraz se puede usar:

filehandle = open("text.txt", "w")
filebuffer = ["hi","welcome","yes yes welcome"]
filehandle.writelines(filebuffer)
filehandle.close()
Sashini Hettiarachchi
fuente
0

También puedes probar filewriter

pip install filewriter

from filewriter import Writer

Writer(filename='my_file', ext='txt') << ["row 1 hi there", "row 2"]

Escribe en my_file.txt

Toma un iterable o un objeto con __str__soporte.

Emin Bugra Saral
fuente
0

Cuando necesito escribir muchas líneas nuevas, defino una lambda que usa una printfunción:

out = open(file_name, 'w')
fwl = lambda *x, **y: print(*x, **y, file=out) # FileWriteLine
fwl('Hi')

Este enfoque tiene la ventaja de que puede utilizar todas las funciones que están disponibles con la printfunción.

Actualización: como menciona Georgy en la sección de comentarios, es posible mejorar aún más esta idea con la partialfunción:

from functools import partial
fwl = partial(print, file=out)

En mi humilde opinión, este es un enfoque más funcional y menos críptico.

MxNx
fuente
2
O de otra manera (probablemente más limpia) para escribir esto: from functools import partial; fwl = partial(print, file=out).
Georgy
@Georgy Su enfoque es tan bueno que se puede dar como una nueva respuesta.
MxNx
1
La idea es la misma que la suya, solo la implementación es un poco diferente. Si lo desea, puede agregarlo en una edición a su respuesta. Estoy bien con eso.
Georgy