Python - write () versus writelines () dan string gabungan

124

Jadi saya belajar Python. Saya menjalani pelajaran dan mengalami masalah di mana saya harus menyingkat banyak sekali target.write()menjadi satu write(), sementara memiliki "\n"antara setiap variabel input pengguna (objek dari write()).

Saya datang dengan:

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

Jika saya mencoba melakukan:

textdoc.write(lines)

Saya mendapatkan kesalahan. Tetapi jika saya mengetik:

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

Maka itu bekerja dengan baik. Mengapa saya tidak dapat menggunakan string untuk baris baru di write()tetapi saya dapat menggunakannya di writelines()?

Python 2.7 Ketika saya mencari di Google, sebagian besar sumber daya yang saya temukan jauh melampaui kepala saya, saya masih orang awam.

AbeLinkon
sumber
linesbukan string dalam contoh Anda. Ini adalah tupel yang terdiri dari enam senar.
Bachsau

Jawaban:

147
  • writelines mengharapkan string yang dapat diulang
  • write mengharapkan satu string.

line1 + "\n" + line2menggabungkan string tersebut menjadi satu string sebelum meneruskannya ke write.

Perhatikan bahwa jika Anda memiliki banyak baris, Anda mungkin ingin menggunakan "\n".join(list_of_lines).

DGH
sumber
50
Lebih khusus lagi, writelinesmengharapkan iterable. Anda dapat menggunakan list, tuple, atau generator.
Mark Ransom
Terima kasih atas jawabannya pak. Saya berasumsi dengan nama (list_of_lines) bahwa saya harus membuat daftar string dan meneruskan ke .join (list)?
AbeLinkon
9
Mengapa Anda harus menggunakan writebukan writelinesjika Anda memiliki banyak baris? Writelines bisa berkinerja lebih baik karena tidak harus membuat string gabungan sementara, hanya melakukan iterasi di atas garis.
Bouke
@ hBy2Py: justru sebaliknya: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D
1
Sebuah string tunggal juga dapat di-iterable dengan Python
natbusa
123

Mengapa saya tidak dapat menggunakan string untuk baris baru di write () tetapi saya dapat menggunakannya di writelines ()?

Idenya adalah sebagai berikut: jika Anda ingin menulis satu string, Anda dapat melakukannya dengan write(). Jika Anda memiliki rangkaian string, Anda dapat menulis semuanya menggunakan writelines().

write(arg)mengharapkan string sebagai argumen dan menulisnya ke file. Jika Anda memberikan daftar string, itu akan memunculkan pengecualian (omong-omong, tunjukkan kesalahan kepada kami!).

writelines(arg)mengharapkan iterable sebagai argumen (objek yang dapat diulang dapat berupa tupel, daftar, string, atau iterator dalam pengertian yang paling umum). Setiap item yang terdapat dalam iterator diharapkan menjadi string. Tuple string adalah apa yang Anda berikan, sehingga semuanya berfungsi.

Sifat string tidak menjadi masalah bagi kedua fungsi tersebut, yaitu mereka hanya menulis ke file apa pun yang Anda berikan. Bagian yang menarik adalah writelines()tidak menambahkan karakter baris baru sendiri, sehingga nama metode sebenarnya bisa sangat membingungkan. Ini sebenarnya berperilaku seperti metode imajiner yang disebut write_all_of_these_strings(sequence).

Berikut ini adalah cara idiomatik di Python untuk menulis daftar string ke file sambil menjaga setiap string di barisnya sendiri:

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

Ini menangani penutupan file untuk Anda. Konstruksi '\n'.join(lines)menggabungkan (menghubungkan) string dalam daftar linesdan menggunakan karakter '\ n' sebagai perekat. Ini lebih efisien daripada menggunakan +operator.

Mulai dari linesurutan yang sama , berakhir dengan keluaran yang sama, tetapi menggunakan writelines():

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

Ini menggunakan ekspresi generator dan secara dinamis membuat string baru yang diakhiri baris. writelines()mengulangi urutan string ini dan menulis setiap item.

Sunting: Hal lain yang harus Anda perhatikan:

write()dan sudah readlines()ada sebelum writelines()diperkenalkan. writelines()diperkenalkan nanti sebagai bagian dari readlines(), sehingga orang dapat dengan mudah menulis konten file yang baru saja dibaca melalui readlines():

outfile.writelines(infile.readlines())

Sungguh, inilah alasan utama mengapa writelinesmemiliki nama yang membingungkan. Juga, hari ini, kami tidak benar-benar ingin menggunakan metode ini lagi. readlines()membaca seluruh file ke memori mesin Anda sebelum writelines()mulai menulis data. Pertama-tama, ini mungkin membuang waktu. Mengapa tidak mulai menulis bagian data sambil membaca bagian lain? Namun, yang terpenting, pendekatan ini bisa sangat memakan memori. Dalam skenario ekstrim, di mana file input lebih besar dari memori mesin Anda, pendekatan ini bahkan tidak akan berfungsi. Solusi untuk masalah ini adalah dengan menggunakan iterator saja. Contoh kerja:

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

Ini membaca file input baris demi baris. Segera setelah satu baris dibaca, baris ini ditulis ke file keluaran. Diucapkan secara skematis, selalu hanya ada satu baris dalam memori (dibandingkan dengan seluruh konten file yang ada di memori dalam kasus pendekatan garis baca / garis tulis).

Dr. Jan-Philip Gehrcke
sumber
5
@AbeLinkon: Saya tidak akan mendukung kesimpulan ini. write()dan writelines()pada dasarnya setara dan penggunaannya juga merupakan masalah selera pribadi. Namun, penting untuk dicatat bahwa untuk daftar string yang sangat panjang (disebut lines) kurang efisien untuk menulis f.write('\n'.join(lines))daripada for l in line: f.write('%s\n' % l). Dalam kasus pertama, string yang sangat baru dan sangat panjang dibuat dalam memori sebelum menulisnya. Dalam kasus kedua, data ditulis sepotong demi sepotong.
Dr. Jan-Philip Gehrcke
3
f.write ('\ n'.join (lines)) tidak menambahkan nl terakhir saat saya menjalankannya.
Jiminion
5
Tentu saja Anda tidak akan melakukannya, outf.writelines(inf.readlines())melainkan outf.writelines(inf). Fungsi yang tidak ingin kita gunakan lagi readlines()tidak writelines().
moooeeeep
2
@moooeeeep: meskipun tidak ada yang salah dengan fungsionalitas / implementasi writelines(), semantiknya, seperti yang dijelaskan, kurang dari ideal. Inilah mengapa saya tidak pernah menggunakannya. Dan saya tidak pernah melewatkannya.
Dr. Jan-Philip Gehrcke
2
@AbeLinkon - mungkin Anda harus mempertimbangkan untuk menerima jawaban ini, ini jelas lebih baik daripada yang Anda terima semula
Peter M. - singkatan dari Monica
-4

jika Anda hanya ingin menyimpan dan memuat daftar coba Pickle

Penghematan acar:

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

dan memuat:

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

Sebenarnya, menurut saya masalahnya adalah variabel "baris" Anda buruk. Anda mendefinisikan baris sebagai tupel, tetapi saya percaya write () membutuhkan string. Yang harus Anda ubah hanyalah koma Anda menjadi plus (+).

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

harus bekerja.

Kevin
sumber
-5

Latihan 16 dari buku Zed Shaw? Anda dapat menggunakan karakter escape sebagai berikut:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()
Gerald
sumber
Solusi yang sangat lemah. Jika Anda ingin menggabungkan beberapa baris dengan cara ini, Anda harus melakukannya seperti ini: " \n ".join((line1, line2, line3)).
Bachsau