Python - write () versus writelines () y cadenas concatenadas

124

Entonces estoy aprendiendo Python. Estoy pasando por las lecciones y me encontré con un problema en el que tuve que condensar muchas target.write()en una sola write(), mientras tenía una "\n"variable de entrada entre cada usuario (el objeto de write()).

Se me ocurrio:

nl = "\n"
lines = line1, nl, line2, nl, line3, nl
textdoc.writelines(lines)

Si trato de hacer:

textdoc.write(lines)

Me sale un error Pero si escribo:

textdoc.write(line1 + "\n" + line2 + ....)

Entonces funciona bien. ¿Por qué no puedo usar una cadena para una nueva línea write()pero puedo usarla writelines()?

Python 2.7 Cuando busqué en Google, la mayoría de los recursos que encontré estaban muy por encima de mi cabeza, todavía soy un laico.

AbeLinkon
fuente
linesno es una cadena en tu ejemplo. Es una tupla que consta de seis cuerdas.
Bachsau

Respuestas:

147
  • writelines espera un iterable de cadenas
  • write espera una sola cadena.

line1 + "\n" + line2combina esas cadenas en una sola cadena antes de pasarla a write.

Tenga en cuenta que si tiene muchas líneas, es posible que desee utilizar "\n".join(list_of_lines).

DGH
fuente
50
Más específicamente, writelinesespera un iterable. Puede usar una lista, una tupla o un generador.
Mark Ransom
Gracias por la respuesta señor. Supongo por el nombre (list_of_lines) que debo hacer una lista de cadenas y pasar luego a .join (list)?
AbeLinkon
9
¿Por qué debería usar en writelugar de writelinessi tiene muchas líneas? Writelines podría tener un mejor rendimiento ya que no tiene que crear una cadena concatenada temporal, simplemente iterando sobre las líneas.
Bouke
@ hBy2Py: exactamente lo contrario: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D
1
Una sola cadena también es iterable en Python
natbusa
122

¿Por qué no puedo usar una cadena para una nueva línea en write () pero puedo usarla en writelines ()?

La idea es la siguiente: si desea escribir una sola cadena, puede hacerlo write(). Si tiene una secuencia de cadenas, puede escribirlas todas usando writelines().

write(arg)espera una cadena como argumento y la escribe en el archivo. Si proporciona una lista de cadenas, generará una excepción (por cierto, ¡nos mostrará errores!).

writelines(arg)espera un iterable como argumento (un objeto iterable puede ser una tupla, una lista, una cadena o un iterador en el sentido más general). Se espera que cada elemento contenido en el iterador sea una cadena. Una tupla de cadenas es lo que proporcionó, por lo que las cosas funcionaron.

La naturaleza de la (s) cadena (s) no es importante para ambas funciones, es decir, simplemente escriben en el archivo lo que sea que les proporcione. La parte interesante es que writelines()no agrega caracteres de nueva línea por sí mismo, por lo que el nombre del método puede ser bastante confuso. En realidad se comporta como un método imaginario llamado write_all_of_these_strings(sequence).

Lo que sigue es una forma idiomática en Python de escribir una lista de cadenas en un archivo mientras mantiene cada cadena en su propia línea:

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.write('\n'.join(lines))

Esto se encarga de cerrar el archivo por usted. La construcción '\n'.join(lines)concatena (conecta) las cadenas en la lista linesy usa el carácter '\ n' como pegamento. Es más eficiente que usar el +operador.

Comenzando desde la misma linessecuencia, terminando con la misma salida, pero usando writelines():

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.writelines("%s\n" % l for l in lines)

Esto hace uso de una expresión generadora y crea dinámicamente cadenas terminadas en nueva línea. writelines()itera sobre esta secuencia de cadenas y escribe cada elemento.

Editar: Otro punto que debe tener en cuenta:

write()y readlines()existía antes de writelines()ser introducido. writelines()se introdujo más tarde como una contraparte de readlines(), para poder escribir fácilmente el contenido del archivo que se acaba de leer mediante readlines():

outfile.writelines(infile.readlines())

Realmente, esta es la razón principal por la que writelinestiene un nombre tan confuso. Además, hoy, ya no queremos usar este método. readlines()lee el archivo completo en la memoria de su máquina antes de writelines()comenzar a escribir los datos. En primer lugar, esto puede perder el tiempo. ¿Por qué no comenzar a escribir partes de datos mientras lee otras partes? Pero, lo más importante, este enfoque puede consumir mucha memoria. En un escenario extremo, donde el archivo de entrada es más grande que la memoria de su máquina, este enfoque ni siquiera funcionará. La solución a este problema es usar solo iteradores. Un ejemplo de trabajo:

with open('inputfile') as infile:
    with open('outputfile') as outfile:
        for line in infile:
            outfile.write(line)

Esto lee el archivo de entrada línea por línea. Tan pronto como se lee una línea, esta línea se escribe en el archivo de salida. Hablando esquemáticamente, siempre hay una sola línea en la memoria (en comparación con todo el contenido del archivo que está en la memoria en el caso del enfoque de líneas de lectura / escrituras).

Dr. Jan-Philip Gehrcke
fuente
55
@AbeLinkon: No apoyaría esta conclusión. write()y writelines()son básicamente equivalentes y su uso también es una cuestión de gusto personal. Sin embargo, es importante tener en cuenta que para una lista extremadamente larga de cadenas (llamada lines) es menos eficiente escribir f.write('\n'.join(lines))que for l in line: f.write('%s\n' % l). En el primer caso, se crea una cadena completamente nueva y muy larga en la memoria antes de escribirla. En el segundo caso, los datos se escriben por partes.
Dr. Jan-Philip Gehrcke
3
f.write ('\ n'.join (líneas)) no agregó el último nl cuando lo ejecuté.
Jiminion
55
Por supuesto que no lo harías, outf.writelines(inf.readlines())sino más bien outf.writelines(inf). La función que ya no queremos usar readlines()no lo es writelines().
moooeeeep
2
@moooeeeep: aunque no hay nada de malo en la funcionalidad / implementación de writelines(), su semántica es, como se explicó, menos que ideal. Es por eso que nunca lo he usado. Y nunca me lo perdí.
Dr. Jan-Philip Gehrcke
2
@AbeLinkon: tal vez deberías considerar aceptar esta respuesta, es claramente mejor que la que aceptaste originalmente
Peter M., representa a Mónica el
-4

si solo quieres guardar y cargar una lista prueba Pickle

Ahorro de pepinillos:

with open("yourFile","wb")as file:
 pickle.dump(YourList,file)

y cargando:

with open("yourFile","rb")as file:
 YourList=pickle.load(file)
Venya
fuente
-5

En realidad, creo que el problema es que sus "líneas" variables son malas. Definió líneas como una tupla, pero creo que write () requiere una cadena. Todo lo que tienes que cambiar son tus comas en más (+).

nl = "\n"
lines = line1+nl+line2+nl+line3+nl
textdoc.writelines(lines)

Deberia trabajar.

Kevin
fuente
-5

¿Ejercicio 16 del libro de Zed Shaw? Puede usar caracteres de escape de la siguiente manera:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()
Gerald
fuente
Solución muy débil. Si quería para concatenar varias líneas de esta manera, usted debe hacerlo de esta manera: " \n ".join((line1, line2, line3)).
Bachsau