2010-06-05 42 views
87

假设我有一个csv.DictReader对象,我想把它写成一个CSV文件。我怎样才能做到这一点?如何使用csv.DictWriter编写标题行?

我知道我可以写行数据这样的:

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) 

但我怎么能包括字段名?

回答

110

编辑:
在2.7/3.2中有a new writeheader() method。另外,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需要一个字段名的参数。
the documentation

的字段名参数标识 的顺序在 字典传递给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) 
+10

+1还有另一种写头的方法:''dw.writerow(dict((f,f)for f in dr.fieldnames)''。 – FMc 2010-06-05 21:15:57

+2

@亚当:对于更短的一行,请参阅我的答案。 – 2010-06-05 23:23:09

+2

@John:+1给你的答案;简单地使用“底层写作者实例”肯定比“费力的身份映射”更可取。 – bernie 2010-06-05 23:39:25

23

有几个选项:

( 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' 
>>> 
+0

目前在Python 3.6中,'extrasaction'功能似乎更好地实现。现在它是'wrong_fields = rowdict.keys() - self.fieldnames,所以它实际上是一个'set'操作。 – martineau 2017-04-29 18:19:06

9

另一种方式做,这将是你的输出加上行前添加,下面一行:

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

拉链将返回n包含相同值的双精度列表。该列表可用于启动字典。

相关问题