Bagaimana cara menulis baris header dengan csv.DictWriter?
114
Asumsikan saya memiliki sebuah csv.DictReaderobjek dan saya ingin menuliskannya sebagai file CSV. Bagaimana saya bisa melakukan ini?
Saya tahu bahwa saya dapat menulis baris data seperti ini:
dr = csv.DictReader(open(f), delimiter='\t')# process my dr object# ...# write out object
output = csv.DictWriter(open(f2,'w'), delimiter='\t')for item in dr:
output.writerow(item)
Edit:
Di 2.7 / 3.2 ada metode baruwriteheader() . Juga, jawaban John Machin memberikan metode yang lebih sederhana untuk menulis baris tajuk.
Contoh sederhana menggunakan writeheader()metode ini sekarang tersedia di 2.7 / 3.2:
from collections importOrderedDict
ordered_fieldnames =OrderedDict([('field1',None),('field2',None)])with open(outfile,'wb')as fou:
dw = csv.DictWriter(fou, delimiter='\t', fieldnames=ordered_fieldnames)
dw.writeheader()# continue on to write data
Membuat instance DictWriter membutuhkan argumen nama bidang.
Dari dokumentasi :
Parameter nama bidang mengidentifikasi urutan di mana nilai dalam kamus yang diteruskan ke metode writerow () ditulis ke csvfile.
Dengan kata lain: Argumen Fieldnames diperlukan karena dicts Python tidak berurutan.
Di bawah ini adalah contoh bagaimana Anda akan menulis header dan data ke sebuah file.
Catatan: withpernyataan telah ditambahkan di 2.6. Jika menggunakan 2.5:from __future__ import with_statement
with open(infile,'rb')as fin:
dr = csv.DictReader(fin, delimiter='\t')# dr.fieldnames contains values from first row of `f`.with open(outfile,'wb')as fou:
dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames)
headers ={}for n in dw.fieldnames:
headers[n]= n
dw.writerow(headers)for row in dr:
dw.writerow(row)
Seperti yang @FM sebutkan dalam komentar, Anda dapat meringkas penulisan header menjadi satu baris, misalnya:
with open(outfile,'wb')as fou:
dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames)
dw.writerow(dict((fn,fn)for fn in dr.fieldnames))for row in dr:
dw.writerow(row)
1 Namun cara lain untuk menulis header: dw.writerow( dict((f,f) for f in dr.fieldnames) ).
FMc
2
@Adam: untuk satu baris yang lebih pendek, lihat jawaban saya.
John Machin
2
@ John: +1 untuk jawaban Anda; hanya menggunakan "contoh penulis yang mendasari" tentu lebih baik daripada "pemetaan identitas yang melelahkan".
mechanical_meat
1
@endolith: terima kasih atas umpan baliknya. Pindahkan bagian itu ke atas jawaban.
mechanical_meat
1
Karena Anda juga menggunakan dictReader, maka mudah untuk menambahkan bidang dengan dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames). Dengan begitu, jika field Anda berubah, Anda tidak perlu mengatur dictWriter.
Spencer Rathbun
29
Beberapa pilihan:
(1) Dengan susah payah membuat pemetaan identitas (yaitu tidak melakukan apa-apa) dari nama bidang Anda sehingga csv.DictWriter dapat mengubahnya kembali ke daftar dan meneruskannya ke instance csv.writer.
(2) Dokumentasi menyebutkan " writercontoh yang mendasari " ... jadi gunakan saja (contoh di akhir).
dw.writer.writerow(dw.fieldnames)
(3) Hindari overhead csv.Dictwriter dan lakukan sendiri dengan csv.writer
Menulis data:
w.writerow([d[k]for k in fieldnames])
atau
w.writerow([d.get(k, restval)for k in fieldnames])
Alih-alih extrasaction"fungsionalitas", saya lebih suka membuat kode sendiri; dengan cara itu Anda dapat melaporkan SEMUA "ekstra" dengan kunci dan nilai, bukan hanya kunci ekstra pertama. Apa gangguan nyata dengan DictWriter adalah bahwa jika Anda telah memverifikasi kunci sendiri saat setiap dict sedang dibuat, Anda harus ingat untuk menggunakan extrasaction = 'ignore' jika tidak, itu akan menjadi SLOWLY (nama bidang adalah daftar) ulangi pemeriksaan:
wrong_fields =[k for k in rowdict if k notin self.fieldnames]
============
>>> f = open('csvtest.csv','wb')>>>import csv
>>> fns ='foo bar zot'.split()>>> dw = csv.DictWriter(f, fns, restval='Huh?')# dw.writefieldnames(fns) -- no such animal>>> dw.writerow(fns)# no such luck, it can't imagine what to do with a listTraceback(most recent call last):File"<stdin>", line 1,in<module>File"C:\python26\lib\csv.py", line 144,in writerow
return self.writer.writerow(self._dict_to_list(rowdict))File"C:\python26\lib\csv.py", line 141,in _dict_to_list
return[rowdict.get(key, self.restval)for key in self.fieldnames]AttributeError:'list' object has no attribute 'get'>>> dir(dw)['__doc__','__init__','__module__','_dict_to_list','extrasaction','fieldnam
es','restval','writer','writerow','writerows']# eureka>>> dw.writer.writerow(dw.fieldnames)>>> dw.writerow({'foo':'oof'})>>> f.close()>>> open('csvtest.csv','rb').read()'foo,bar,zot\r\noof,Huh?,Huh?\r\n'>>>
Saat ini di Python 3.6, extrasactionfungsinya tampaknya diterapkan dengan lebih baik. Sekarang wrong_fields = rowdict.keys() - self.fieldnames so it's effectively a operasi disetel.
martineau
Saya memberikan suara untuk jawaban ini untuk komentar 'hindari DictWriter' - saya belum melihat keuntungan apa pun untuk menggunakannya, dan tampaknya lebih cepat menyusun data Anda dan menggunakan csv.writer
neophytte
8
Cara lain untuk melakukan ini adalah dengan menambahkan sebelum menambahkan baris dalam output Anda, baris berikut:
dw.writerow( dict((f,f) for f in dr.fieldnames) )
.dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames)
. Dengan begitu, jika field Anda berubah, Anda tidak perlu mengatur dictWriter.Beberapa pilihan:
(1) Dengan susah payah membuat pemetaan identitas (yaitu tidak melakukan apa-apa) dari nama bidang Anda sehingga csv.DictWriter dapat mengubahnya kembali ke daftar dan meneruskannya ke instance csv.writer.
(2) Dokumentasi menyebutkan "
writer
contoh yang mendasari " ... jadi gunakan saja (contoh di akhir).(3) Hindari overhead csv.Dictwriter dan lakukan sendiri dengan csv.writer
Menulis data:
atau
Alih-alih
extrasaction
"fungsionalitas", saya lebih suka membuat kode sendiri; dengan cara itu Anda dapat melaporkan SEMUA "ekstra" dengan kunci dan nilai, bukan hanya kunci ekstra pertama. Apa gangguan nyata dengan DictWriter adalah bahwa jika Anda telah memverifikasi kunci sendiri saat setiap dict sedang dibuat, Anda harus ingat untuk menggunakan extrasaction = 'ignore' jika tidak, itu akan menjadi SLOWLY (nama bidang adalah daftar) ulangi pemeriksaan:============
sumber
extrasaction
fungsinya tampaknya diterapkan dengan lebih baik. Sekarangwrong_fields = rowdict.keys() - self.fieldnames so it's effectively a
operasi disetel.Cara lain untuk melakukan ini adalah dengan menambahkan sebelum menambahkan baris dalam output Anda, baris berikut:
Zip akan mengembalikan daftar doublet yang berisi nilai yang sama. Daftar ini dapat digunakan untuk memulai kamus.
sumber