วิธีเขียน header row ด้วย csv.DictWriter


114

สมมติว่าฉันมีcsv.DictReaderวัตถุและต้องการเขียนเป็นไฟล์ CSV ฉันจะทำเช่นนี้ได้อย่างไร?

ฉันรู้ว่าฉันสามารถเขียนแถวของข้อมูลได้ดังนี้:

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)

แต่ฉันจะรวมชื่อเขตข้อมูลได้อย่างไร

คำตอบ:


149

แก้ไข:
ใน 2.7 / 3.2 มีใหม่writeheader()วิธีการ นอกจากนี้คำตอบของ John Machin ยังให้วิธีการเขียนแถวส่วนหัวที่ง่ายกว่า
ตัวอย่างง่ายๆของการใช้writeheader()วิธีนี้มีอยู่ใน 2.7 / 3.2:

from collections import OrderedDict
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

การสร้างอินสแตนซ์ DictWriter ต้องการอาร์กิวเมนต์ชื่อฟิลด์
จากเอกสารประกอบ :

พารามิเตอร์ชื่อฟิลด์ระบุลำดับที่ค่าในพจนานุกรมส่งผ่านไปยังเมธอด writerow () ไปยัง csvfile

อีกวิธีหนึ่ง: จำเป็นต้องใช้อาร์กิวเมนต์ชื่อฟิลด์เนื่องจากคำสั่ง Python ไม่เรียงลำดับโดยเนื้อแท้
ด้านล่างนี้คือตัวอย่างวิธีการเขียนส่วนหัวและข้อมูลลงในไฟล์
หมายเหตุ: withคำสั่งถูกเพิ่มใน 2.6 หากใช้ 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)

ตามที่ @FM กล่าวถึงในความคิดเห็นคุณสามารถย่อส่วนการเขียนส่วนหัวให้เป็นซับในเช่น:

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)

12
+1 อีกวิธีหนึ่งในการเขียนส่วนหัว: dw.writerow( dict((f,f) for f in dr.fieldnames) ).
FMc

2
@Adam: สำหรับซับสั้น ๆ ดูคำตอบของฉัน
John Machin

2
@ จอห์น: +1 คำตอบของคุณ; การใช้ "อินสแตนซ์นักเขียนที่เป็นพื้นฐาน" นั้นดีกว่าอย่างแน่นอนสำหรับ "การทำแผนที่ระบุตัวตน"
mechanical_meat

1
@endolith: ขอบคุณสำหรับคำติชม ย้ายส่วนนั้นไปที่ด้านบนของคำตอบ
mechanical_meat

1
เนื่องจากคุณกำลังใช้ dictReader dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames)เช่นกันแล้วมันเป็นเรื่องง่ายที่จะเพิ่มฟิลด์ด้วย ด้วยวิธีนี้หากเขตข้อมูลของคุณเปลี่ยนไปคุณไม่จำเป็นต้องปรับแต่ง dictWriter
Spencer Rathbun

29

ตัวเลือกบางอย่าง:

(1) สร้างการแมปข้อมูลประจำตัว (เช่นไม่ต้องทำอะไรเลย) เขียนออกมาจากชื่อฟิลด์ของคุณเพื่อให้ csv.DictWriter สามารถแปลงกลับเป็นรายการและส่งต่อไปยังอินสแตนซ์ csv.writer

(2) เอกสารกล่าวถึง " writerอินสแตนซ์พื้นฐาน" ... ดังนั้นใช้มัน (ตัวอย่างตอนท้าย)

dw.writer.writerow(dw.fieldnames)

(3) หลีกเลี่ยง csv.Dictwriter เหนือศีรษะและทำด้วยตัวเองด้วย csv.writer

การเขียนข้อมูล:

w.writerow([d[k] for k in fieldnames])

หรือ

w.writerow([d.get(k, restval) for k in fieldnames])

แทนที่จะเป็นextrasaction"ฟังก์ชัน" ฉันต้องการเขียนโค้ดด้วยตัวเอง ด้วยวิธีนี้คุณสามารถรายงาน "พิเศษ" ทั้งหมดด้วยคีย์และค่าไม่ใช่เฉพาะคีย์พิเศษแรก สิ่งที่สร้างความรำคาญให้กับ DictWriter ก็คือหากคุณได้ตรวจสอบคีย์ด้วยตัวเองในขณะที่สร้างคำสั่งแต่ละตัวคุณต้องจำไว้ว่าให้ใช้ความพิเศษ = 'ไม่สนใจ' มิฉะนั้นจะช้าลง (ชื่อฟิลด์คือรายการ) ทำเครื่องหมายซ้ำ:

wrong_fields = [k for k in rowdict if k not in 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 list
Traceback (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'
>>>

ขณะนี้อยู่ใน Python 3.6 การextrasactionทำงานดูเหมือนจะใช้งานได้ดีขึ้น ตอนนี้ตั้งwrong_fields = rowdict.keys() - self.fieldnames so it's effectively a ค่าการดำเนินการแล้ว
martineau

ฉันโหวตคำตอบนี้สำหรับความคิดเห็น 'หลีกเลี่ยง DictWriter' - ฉันไม่เห็นประโยชน์ใด ๆ ในการใช้มันและดูเหมือนว่าจะจัดโครงสร้างข้อมูลของคุณได้เร็วขึ้นและใช้ csv.writer
neophytte

8

อีกวิธีในการทำเช่นนี้คือเพิ่มก่อนเพิ่มบรรทัดในผลลัพธ์ของคุณบรรทัดต่อไปนี้:

output.writerow(dict(zip(dr.fieldnames, dr.fieldnames)))

zip จะส่งคืนรายการ doublet ที่มีค่าเดียวกัน รายการนี้สามารถใช้เพื่อเริ่มต้นพจนานุกรม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.