Csv.DictWriter ile başlık satırı nasıl yazılır?


114

Bir nesnem olduğunu csv.DictReaderve bunu bir CSV dosyası olarak yazmak istediğimi varsayın . Bunu nasıl yapabilirim?

Veri satırlarını şöyle yazabileceğimi biliyorum :

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)

Ancak alan adlarını nasıl ekleyebilirim?

Yanıtlar:


149

Düzenleme:
2.7 / 3.2'de yeni bir writeheader()yöntem var . Ayrıca, John Machin'in cevabı, başlık satırını yazmak için daha basit bir yöntem sağlar. Şimdi 2.7 / 3.2'de
bulunan writeheader()yöntemi kullanmanın basit bir örneği :

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 örneğinin oluşturulması, bir alan adları bağımsız değişkeni gerektirir.
Gönderen belgeler :

Fieldnames parametresi, writerow () yöntemine iletilen sözlükteki değerlerin csv dosyasına yazılma sırasını tanımlar.

Başka bir deyişle: Alan adları argümanı gereklidir çünkü Python diktleri doğaları gereği sırasızdır.
Aşağıda başlığı ve verileri bir dosyaya nasıl yazacağınıza dair bir örnek verilmiştir.
Not: withaçıklama 2.6'da eklendi. 2.5 kullanılıyorsa: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'nin bir yorumda bahsettiği gibi, başlık yazmayı tek satırlık olarak daraltabilirsiniz, örneğin:

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 Yine başka bir yolu başlığını yazmak için: dw.writerow( dict((f,f) for f in dr.fieldnames) ).
FMc

2
@Adam: Daha kısa bir tek satırlık için cevabıma bakın.
John Machin

2
@John: Cevabınıza +1; basitçe "temelde yatan yazıcı örneğini" kullanmak, "zahmetli kimlik haritalamaya" kesinlikle tercih edilir.
mechanical_meat

1
@endolith: Geri bildirim için teşekkürler. Bu kısım cevabın üstüne taşındı.
mechanical_meat

1
Bir dictReader da kullandığınız için, alanları eklemek kolaydır dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames). Bu şekilde, alanlarınız değişirse, dictWriter'ı ayarlamanıza gerek kalmaz.
Spencer Rathbun

29

Birkaç seçenek:

(1) Csv.DictWriter'ın onu bir listeye dönüştürebilmesi ve bir csv.writer örneğine aktarabilmesi için, zahmetli bir şekilde alan adlarınızdan bir kimlik eşlemesi yapın (yani hiçbir şey yapmayın).

(2) Dokümantasyon "temelde yatan writer örnekten" ... bu yüzden sadece onu kullanın (sondaki örnek).

dw.writer.writerow(dw.fieldnames)

(3) csv.Dictwriter ek yükünden kaçının ve csv.writer ile kendiniz yapın

Veri yazma:

w.writerow([d[k] for k in fieldnames])

veya

w.writerow([d.get(k, restval) for k in fieldnames])

extrasaction"İşlevsellik" yerine, kendim kodlamayı tercih ederim; bu şekilde, yalnızca ilk ekstra anahtarla değil, anahtarlar ve değerlerle birlikte TÜM "ekstraları" bildirebilirsiniz. DictWriter ile gerçek bir sıkıntı, her bir dikte oluşturulurken anahtarları kendiniz doğruladıysanız, extrasaction = 'ignore' kullanmayı hatırlamanız gerekir, aksi takdirde YAVAŞÇA (alan adları bir listedir) kontrolü tekrarlayın:

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

Şu anda Python 3.6'da, extrasactionişlevsellik daha iyi uygulanıyor gibi görünüyor. Şimdi wrong_fields = rowdict.keys() - self.fieldnames so it's effectively a ayarlandı.
martineau

Bu yanıtı 'DictWriter'dan kaçının' yorumu için oyluyorum - kullanmanın herhangi bir avantajı görmedim ve verilerinizi yapılandırmak ve csv.writer'ı kullanmak daha hızlı görünüyor
neophytte

8

Bunu yapmanın başka bir yolu da çıktınıza satır eklemeden önce aşağıdaki satırı eklemektir:

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

Zip, aynı değeri içeren ikilinin bir listesini döndürür. Bu liste bir sözlüğü başlatmak için kullanılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.