[Tutor] write dictionary to file

Steven D'Aprano steve at pearwood.info
Sat Jun 21 06:35:16 CEST 2014


On Fri, Jun 20, 2014 at 08:38:52AM +0000, Ian D wrote:
> This is driving me nuts.
> 
> I have tried many different things, but I just do not understand this 
> csv library.

Have you tried reading the documentation? It sounds like you're just 
throwing random bits of code at it and hoping something works.

A better approach is to slow down and try to understand what the csv is 
doing, what it expects from you, and how you can best use it. Ask 
*focused* questions, rather than just blast us with blobs of code over 
and over again.


> #so far this should read a file
> #using dictreader and take a column and join some text onto it
> 
> import csv
> 
> csvfile= open('StudentListToSort.csv', newline='')
> spamreader = csv.DictReader(csvfile,delimiter=',',quotechar='|')

Are you sure that your input file uses | as a quote character and , as 
the field delimiter? 


> #open a file to write to later
> fields = ['user','first','last','password','year']
> csvoutput = open('output.csv', 'wb+')

I'm pretty sure you don't want to use "wb+" mode. Since you're using 
Python 3, I think you should just use "w" mode.

The "b" turns on binary mode, and in Python 3 you don't want that. The 
"+" turns on either "read/write" mode or "append" mode, I don't remember 
which, but either way I don't think it's necessary for what you are 
doing.


> spamwriter = csv.DictWriter(csvoutput,fieldnames=fields, delimiter=' ')

Now you're turning every , delimiter into a space. Are you sure you want 
that?


> for row in spamreader:
>     if row['year'] == '40':     
>         username = row['user'] 
>         email = "".join([username,'@email.com]) 

Syntax error: you left out the closing single quote. You need:

    email = "".join([username,'@email.com'])


Other than that, so far so good. You're going through each row of the 
input file, extracting the "year" field, checking if it equals "40", and 
if it is, creating an email address from the user field. Perhaps a 
shorter way to do this would be:

    email = row['user'] + '@email.com'


rather than mucking about with "".join for only two pieces of text.


>         output = row['user'], row['first'],row['last'],row['password'],row['year']

I'd move the print(output) line directly under this line, so it will 
print the output even if the following line fails.

>         spamwriter.writerow([spamreader[fields] for fieldnames in fields])
>         print(output)

I'm sure the writerow line is completely wrong :-(

It expects a dict {fieldname: fieldvalue} not a list [fieldvalue]. And 
you extract the field values through row, not through the spamreader 
object directly. Try this instead:

    spamwriter.writerow({name: row[name] for name in fields})


Let me put all those changes together, plus a few more fixes. Take note 
of my comments.



import csv

# Open the file we're reading from.
csvfile= open('StudentListToSort.csv', newline='')
# Open a file to write to.
csvoutput = open('output.csv', 'w', newline='')

fields = ['user', 'first', 'last', 'password', 'year']

# Are you sure you want | as the quote character?
spamreader = csv.DictReader(csvfile, delimiter=',', quotechar='|')

# Still using , as a delimiter, not space.
spamwriter = csv.DictWriter(csvoutput, fieldnames=fields, delimiter=',')

for row in spamreader:
    if row['year'] == '40':
        email = row['user'] + '@email.com'
        output = [ row[fieldname] for fieldname in fields ]
        print(output)
        # DictWriter needs a dict, not a list.
        spamwriter.writerow({name: row[name] for name in fields})
        print("Warning: email calculated but never used:", email)

# Good practice is to close the files when done.
csvfile.close()
csvoutput.close()




Try that. If you get any errors, please COPY AND PASTE the ***entire*** 
traceback, not just the last line.


-- 
Steven


More information about the Tutor mailing list