2010-06-05 16 views
87

Supongamos que tengo un objeto csv.DictReader y quiero escribirlo como un archivo CSV. ¿Cómo puedo hacer esto?Cómo escribir una fila de encabezado con csv.DictWriter?

sé que puedo escribir los filas de datos así:

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) 

Pero, ¿cómo puedo incluir los nombres de campo?

Respuesta

110

Edit:
En 2.7/3.2 hay a new writeheader() method. Además, la respuesta de John Machin proporciona un método más simple para escribir la fila del encabezado.
ejemplo simple de utilizar el método writeheader() ahora disponible en 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 

instanciar DictWriter requiere un argumento nombres de campos.
De the documentation:

El parámetro nombres de campo identifica el orden en que los valores en el diccionario pasado a la writerow() método se escriben en el csvfile.

Dicho de otra manera: El argumento Fieldnames es necesario porque los dictados de Python son intrínsecamente desordenados.
A continuación se muestra un ejemplo de cómo escribiría el encabezado y los datos en un archivo.
Nota: la declaración with se agregó en 2.6. Si el uso de 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) 

Como @FM menciones en un comentario, puede condensarse cabecera de la escritura en un sola línea, por ejemplo:

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 Otra forma más de escribir el encabezado: 'dw.writerow (dict ((f, f) para f en dr.fieldnames))'. – FMc

+2

@ Adam: para un one-liner más corto, vea mi respuesta. –

+2

@John: +1 a su respuesta; simplemente utilizar "la instancia de escritor subyacente" es ciertamente preferible a "mapeo de identidad laborioso". – bernie

23

algunas opciones:

(1) Laboriosamente haga una asignación de identidad (es decir, no haga nada) dict fuera de sus nombres de campo para que csv.DictWriter pueda convertirlo de nuevo a una lista y pasarlo a una instancia de csv.writer.

(2) La documentación menciona "la instancia subyacente writer" ... así que solo úsala (ejemplo al final).

dw.writer.writerow(dw.fieldnames) 

(3) Evitar la sobrecarga csv.Dictwriter y hacerlo tu mismo con csv.writer

escritura de datos:

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

o

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

En lugar de la extrasaction "funcionalidad", preferiría codificarlo yo mismo; de esa manera puede reportar TODOS los "extras" con las claves y valores, no solo con la primera clave adicional.Lo que es realmente una molestia con DictWriter es que si ha verificado las claves usted mismo cuando se está construyendo cada dict, debe recordar usar extrasaction = 'ignore'; de lo contrario, se va a LENTAMENTE (los nombres de los campos es una lista) repite el cheque:

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

Actualmente en Python 3.6, la funcionalidad 'extrasaction' parece implementada mejor. Ahora es 'wrong_fields = rowdict.keys() - self.fieldnames por lo que es efectivamente una operación' set'. – martineau

9

Otra manera de hacer esto sería añadir antes de añadir líneas en su salida, la siguiente línea:

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

La cremallera retornaría n una lista de dobletes que contiene el mismo valor. Esta lista podría usarse para iniciar un diccionario.

Cuestiones relacionadas