Як написати рядок заголовка за допомогою 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()метод . Також відповідь Джона Макіна забезпечує більш простий метод написання рядка заголовка.
Простий приклад використання 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.

По-іншому: аргумент 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)

12
+1 Ще один спосіб написати заголовок: dw.writerow( dict((f,f) for f in dr.fieldnames) ).
FMc

2
@Adam: для коротшого однокласника дивіться мою відповідь.
Джон Махін

2
@John: +1 до вашої відповіді; просто використання "основного екземпляра письменника", безумовно, є кращим перед "трудомістким відображенням ідентичності".
Mechan_meat

1
@endolith: дякую за відгуки. Перемістив цю частину до початку відповіді.
mechanical_meat

1
Оскільки ви також використовуєте dictReader, поля легко додавати за допомогою dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames). Таким чином, якщо ваші поля змінюються, вам не потрібно коригувати dictWriter.
Спенсер Ратбун

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', інакше це буде SLOWLY (імена полів - це список), повторіть перевірку:

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 налаштовано операцію.
мартіно

Я голосую за цю відповідь за коментар "уникнути DictWriter" - я не бачив жодної переваги в їх використанні, і здається, швидше структурувати ваші дані та використовувати csv.writer
neophytte

8

Інший спосіб зробити це - додати до додавання рядків у висновок наступний рядок:

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

Zip поверне список дублетів, що містять те саме значення. Цей список може бути використаний для ініціювання словника.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.