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 lines
e utilizza il carattere "\ n" come collante. È più efficiente rispetto all'utilizzo +
dell'operatore.
Partendo dalla stessa lines
sequenza, 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 writelines
ha 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).
lines
non è una stringa nel tuo esempio. È una tupla composta da sei stringhe.