如何使用csv.DictWriter写入标题行?

131 投票
4 回答
180931 浏览
提问于 2025-04-15 23:36

假设我有一个 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)

但是我该怎么把字段名也包含进去呢?

4 个回答

8

另一种方法是在输出中添加行之前,先加上以下这一行:

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

这个zip函数会返回一个包含相同值的双元组列表。这个列表可以用来创建一个字典。

31

有几个选择:

(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',否则它会慢慢地(因为 fieldnames 是一个列表)重复检查:

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'
>>>
176

编辑:
在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()方法的字典中值的写入顺序。

换句话说:fieldnames参数是必须的,因为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)

撰写回答