Как написать строку заголовка с помощью csv.DictWriter?
Предположим, у меня есть объект 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)
Но как включить имена полей?
Ответы
Ответ 1
Edit:
В 2.7/3.2 существует новый writeheader()
метод. Кроме того, ответ Джона Мачина дает более простой способ записи строки заголовка.
Простой пример использования метода 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 требуется аргумент fieldnames.
Из документация:
Параметр fieldnames определяет порядок, в котором значения в словарь, переданный в writerow() метод записывается в csvfile.
Поставить другим способом: Аргумент Fieldnames требуется, потому что Python dicts по своей сути неупорядочен.
Ниже приведен пример того, как вы должны писать заголовок и данные в файл.
Примечание: оператор 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)
Ответ 2
Несколько вариантов:
(1) Сложно сделать идентификационное сопоставление (т.е. do-nothing) из ваших имен полей, чтобы 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, заключается в том, что, если вы сами проверили ключи сами по мере того, как строился каждый dict, вам нужно помнить, что нужно использовать 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'
>>>
Ответ 3
Другой способ сделать это - добавить перед добавлением строк в ваш вывод, следующую строку:
output.writerow(dict(zip(dr.fieldnames, dr.fieldnames)))
Zip вернет список дублетов, содержащих одно и то же значение. Этот список можно использовать для запуска словаря.