Python - write () contro writelines () e stringhe concatenate


124

Quindi sto imparando Python. Sto seguendo le lezioni e mi sono imbattuto in un problema in cui ho dovuto condensarne un gran numero target.write()in un unico write(), pur avendo una "\n"variabile di input tra ogni utente (l'oggetto di write()).

Ho pensato:

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

Se provo a fare:

textdoc.write(lines)

Ottengo un errore. Ma se digito:

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

Allora funziona bene. Perché non riesco a usare una stringa per una nuova riga in write()ma posso usarla in writelines()?

Python 2.7 Quando ho cercato su Google la maggior parte delle risorse che ho trovato erano sopra la mia testa, sono ancora un laico.


linesnon è una stringa nel tuo esempio. È una tupla composta da sei stringhe.
Bachsau

Risposte:


147
  • writelines si aspetta un iterabile di stringhe
  • write si aspetta una singola stringa.

line1 + "\n" + line2unisce queste stringhe in una singola stringa prima di passarla a write.

Nota che se hai molte linee, potresti voler usare "\n".join(list_of_lines).


50
Più specificamente, si writelinesaspetta un iterabile. Puoi usare un elenco, una tupla o un generatore.
Mark Ransom,

Grazie per la risposta, signore. Sto assumendo dal nome (list_of_lines) che dovrei fare un elenco di stringhe e passare poi in .join (list)?
AbeLinkon,

9
Perché dovresti usare writeinvece di writelinesse hai molte linee? Writelines potrebbe essere più performante in quanto non deve creare una stringa concatenata temporanea, ma solo iterare sulle righe.
Bouke

@ hBy2Py: esattamente l'opposto: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D

1
Una singola stringa è anche un iterabile in Python
natbusa

123

Perché non riesco a usare una stringa per una nuova riga in write () ma posso usarla in writelines ()?

L'idea è la seguente: se vuoi scrivere una singola stringa puoi farlo con write(). Se hai una sequenza di stringhe puoi scriverle tutte usando writelines().

write(arg)si aspetta una stringa come argomento e la scrive nel file. Se fornisci un elenco di stringhe, solleverà un'eccezione (a proposito, mostraci gli errori!).

writelines(arg)si aspetta un iterabile come argomento (un oggetto iterabile può essere una tupla, una lista, una stringa o un iteratore nel senso più generale). Ogni elemento contenuto nell'iteratore dovrebbe essere una stringa. Una tupla di stringhe è ciò che hai fornito, quindi le cose hanno funzionato.

La natura della stringa (o delle stringhe) non ha importanza per entrambe le funzioni, cioè scrivono semplicemente nel file qualunque cosa tu fornisca loro. La parte interessante è che writelines()non aggiunge caratteri di nuova riga da solo, quindi il nome del metodo può effettivamente creare confusione. In realtà si comporta come un metodo immaginario chiamato write_all_of_these_strings(sequence).

Quello che segue è un modo idiomatico in Python per scrivere un elenco di stringhe in un file mantenendo ogni stringa nella propria riga:

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

Questo si occupa di chiudere il file per te. Il costrutto '\n'.join(lines)concatena (collega) le stringhe nell'elenco linese utilizza il carattere "\ n" come collante. È più efficiente rispetto all'utilizzo +dell'operatore.

Partendo dalla stessa linessequenza, finendo con lo stesso output, ma utilizzando writelines():

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

Questo fa uso di un'espressione del generatore e crea dinamicamente stringhe con terminazione di nuova riga. writelines()itera su questa sequenza di stringhe e scrive ogni elemento.

Modifica: un altro punto di cui dovresti essere a conoscenza:

write()ed readlines()esisteva prima che writelines()fosse introdotto. writelines()è stato introdotto in seguito come controparte di readlines(), in modo che si potesse facilmente scrivere il contenuto del file che è stato appena letto tramite readlines():

outfile.writelines(infile.readlines())

In realtà, questo è il motivo principale per cui writelinesha un nome così confuso. Inoltre, oggi, non vogliamo più utilizzare questo metodo. readlines()legge l'intero file nella memoria della macchina prima di writelines()iniziare a scrivere i dati. Prima di tutto, questo potrebbe far perdere tempo. Perché non iniziare a scrivere parti di dati mentre si leggono altre parti? Ma, soprattutto, questo approccio può richiedere molto memoria. In uno scenario estremo, in cui il file di input è più grande della memoria della macchina, questo approccio non funzionerà nemmeno. La soluzione a questo problema è utilizzare solo gli iteratori. Un esempio funzionante:

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

Questo legge il file di input riga per riga. Non appena viene letta una riga, questa viene scritta nel file di output. Schematicamente detto, c'è sempre una sola riga in memoria (rispetto all'intero contenuto del file che è in memoria nel caso dell'approccio readlines / writelines).


5
@AbeLinkon: non sosterrei questa conclusione. write()e writelines()sono sostanzialmente equivalenti e anche il loro utilizzo è una questione di gusto personale. Tuttavia, è importante notare che per un elenco estremamente lungo di stringhe (chiamate lines) è meno efficiente da scrivere f.write('\n'.join(lines))rispetto a for l in line: f.write('%s\n' % l). Nel primo caso, una stringa completamente nuova e molto lunga viene creata in memoria prima di scriverla. Nel secondo caso i dati vengono scritti a pezzi.
Dr. Jan-Philip Gehrcke

3
f.write ('\ n'.join (righe)) non ha aggiunto l'ultimo nl quando l'ho eseguito.
Jiminion

5
Ovviamente non lo faresti, outf.writelines(inf.readlines())ma piuttosto outf.writelines(inf). La funzione che non vogliamo più usare readlines()non lo è writelines().
moooeeeep

2
@moooeeeep: sebbene nulla sia sbagliato nella funzionalità / implementazione di writelines(), la sua semantica è, come spiegato, tutt'altro che ideale. Questo è il motivo per cui non l'ho mai usato. E non l'ho mai perso.
Dr. Jan-Philip Gehrcke

2
@AbeLinkon - forse dovresti considerare di accettare questa risposta, è chiaramente migliore di quella che hai inizialmente accettato
Peter M. - sta per Monica

-4

se vuoi solo salvare e caricare un elenco prova Pickle

Risparmio di sottaceti:

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

e caricamento:

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

-5

In realtà, penso che il problema sia che la tua variabile "linee" è pessima. Hai definito le righe come una tupla, ma credo che write () richieda una stringa. Tutto quello che devi cambiare sono le virgole in più (+).

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

dovrebbe funzionare.


-5

Esercizio 16 dal libro di Zed Shaw? Puoi usare i caratteri di escape come segue:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()

Soluzione molto debole. Se si voleva di concatenare diverse linee in questo modo, si dovrebbe fare in questo modo: " \n ".join((line1, line2, line3)).
Bachsau
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.