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の答えは、ヘッダー行を書き込むより簡単な方法を提供します。2.7 / 3.2で利用可能になっ
writeheader()メソッドを使用する簡単な例:

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をインスタンス化するには、fieldnames引数が必要です。ドキュメント
から:

fieldnamesパラメータは、writerow()メソッドに渡されたディクショナリの値がcsvfileに書き込まれる順序を識別します。

言い換えると、Python dictは本質的に順序付けされていないため、Fieldnames引数が必要です。
以下は、ヘッダーとデータをファイルに書き込む方法の例です。
注: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がコメントで言及しているように、ヘッダーの書き込みを1行にまとめることができます。例:

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、2012

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の本当の厄介な点は、各辞書が作成されているときに自分でキーを検証した場合、extrasaction = 'ignore'を使用することを忘れないでください。

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 set`操作です。
martineau

私は「avoid DictWriter」コメントのためにこの回答に投票しています-私はそれを使用する利点を何も見ていません。データを構造化してcsv.writerを使用する方が速いようです
neophytte

8

これを行う別の方法は、出力に次の行を追加する前に追加することです。

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

zipは、同じ値を含むダブレットのリストを返します。このリストは、辞書を開始するために使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.