122

I've got a dictionary:

mydict = {key1: value_a, key2: value_b, key3: value_c}

I want to write the data to a file dict.csv, in this style:

key1: value_a
key2: value_b
key3: value_c

I wrote:

import csv
f = open('dict.csv','wb')
w = csv.DictWriter(f,mydict.keys())
w.writerow(mydict)
f.close()

But now I have all keys in one row and all values in the next row..

When I manage to write a file like this, I also want to read it back to a new dictionary.

Just to explain my code, the dictionary contains values and bools from textctrls and checkboxes (using wxpython). I want to add "Save settings" and "Load settings" buttons. Save settings should write the dictionary to the file in the mentioned way (to make it easier for the user to edit the csv file directly), load settings should read from the file and update the textctrls and checkboxes.

martineau
  • 119,623
  • 25
  • 170
  • 301
user1106770
  • 1,389
  • 4
  • 12
  • 14
  • 1
    can you provide a better example of what you want as output? the "style" you have above is not CSV. are you looking for `key1, value_a [linebreak] key2, value_b [linebreak] key3, value_c`? – tkone Dec 31 '11 at 02:09
  • Another approach is to use `repr()` to write the dict out and then eval the string when you read it in. Look at this [old SO post](http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python) for a discussions of `str()` vs. `repr()`, and [the docs](http://docs.python.org/library/functions.html#repr), too. – Peter Rowell Dec 31 '11 at 02:18
  • Apart from my answer below, if you prefer something a little more sophisticated than just a plain CSV file, you may want to check the `ConfigParser` module – Ricardo Cárdenes Dec 31 '11 at 02:29
  • 3
    What you describe is the typical CSV format written out by the csv module. If you write out multiple dicts with the same keys, the keys are written only once, in the first line, with one line per dict for the corresponding values, in the proper order to line up with the keys in line 1. – PaulMcG Dec 31 '11 at 03:27

8 Answers8

241

The DictWriter doesn't work the way you expect.

with open('dict.csv', 'w') as csv_file:  
    writer = csv.writer(csv_file)
    for key, value in mydict.items():
       writer.writerow([key, value])

To read it back:

with open('dict.csv') as csv_file:
    reader = csv.reader(csv_file)
    mydict = dict(reader)

which is quite compact, but it assumes you don't need to do any type conversion when reading

Ricardo Cárdenes
  • 9,004
  • 1
  • 21
  • 34
  • 2
    Mmh... Just noticed that you wanted a specific format which is not exactly CSV-like. Assumed that you wanted CSV style (ie. a row per key-value pair) because you were using the CSV module... – Ricardo Cárdenes Dec 31 '11 at 02:25
  • 3
    Or... in case the CSV approach is exactly what you wanted, but you prefer ":" as a separator, just add `delimiter=':'` when creating the writer and the reader :) – Ricardo Cárdenes Dec 31 '11 at 02:28
  • writing and reading works fine now, but I would also like to update my checkboxes and textctrls according to the values in my dictionary. I have all my widgets in "def create_controls", which is called when I start my program. But simply calling it again after reading from my csv doesn't update the state of my widgets... Do you know what is the best and simplest way to update/refresh them? – user1106770 Dec 31 '11 at 14:12
  • Depends on your widget library and other factors. I'd suggest to post another question, with a little piece of sample code where you create a couple of controls, and then ask who to refresh them :) – Ricardo Cárdenes Dec 31 '11 at 14:19
  • Certainly, @Kevin. Fixed – Ricardo Cárdenes Sep 30 '15 at 22:50
  • 2
    Note, you should close the file between writing and reading. See what happened in this question/answer: http://stackoverflow.com/a/38467563/235698 – Mark Tolonen Jul 19 '16 at 20:10
  • 1
    @MarkTolonen certainly, using `with` would be better. I'll change the examples to reflect it... – Ricardo Cárdenes Jul 19 '16 at 22:47
  • @SmallChess indeed... must have been on drugs back then, or something. – Ricardo Cárdenes Dec 06 '18 at 21:32
  • (Actually, I used `"wb"` because of the original question! I had forgotten about it) – Ricardo Cárdenes Nov 15 '19 at 00:26
  • Why is it necessary to specify the 'newline' argument here ? – DareYang Apr 23 '20 at 03:50
  • 1
    @DareYang sorry for the delay. Actually, I'm not sure why I wrote it back then. It's not needed. When writing, the effect of this is to leave newline characters untranslated (ie. if you write `\n`, you'll get `\n` in the file). If left alone, "universal mode" kicks in and newlines get translated to the default for the current operating system. Given that it's not really useful here (except if you want to have predictable newlines), I'll remove it. – Ricardo Cárdenes Jun 02 '20 at 21:42
  • Those, who are getting extra newlines in the csv file can check: https://stackoverflow.com/questions/3191528/csv-in-python-adding-an-extra-carriage-return-on-windows – mhc Jan 18 '23 at 16:04
38

Just to give an option, writing a dictionary to csv file could also be done with the pandas package. With the given example it could be something like this:

mydict = {'key1': 'a', 'key2': 'b', 'key3': 'c'}

import pandas as pd

(pd.DataFrame.from_dict(data=mydict, orient='index')
   .to_csv('dict_file.csv', header=False))

The main thing to take into account is to set the 'orient' parameter to 'index' inside the from_dict method. This lets you choose if you want to write each dictionary key in a new row.

Additionaly, inside the to_csv method the header parameter is set to False just to have only the dictionary elements without annoying rows. You can always set column and index names inside the to_csv method.

Your output would look like this:

key1,a
key2,b
key3,c

If instead you want the keys to be the column's names, just use the default 'orient' parameter that is 'columns', as you could check in the documentation links.

Considering the comment from @Rabarberski, when using orient='columns you should configure data as follows:

d = {k: [v] for k, v in mydict.items()}

Ivan Calderon
  • 580
  • 6
  • 14
  • 2
    Excellent worked like a charm :). My value was a list and it generated my csv with all list values in multiple cells and mapped to key in first column. – vinsinraw Feb 14 '19 at 20:41
  • 1
    The last remark about "keys to be column's names" is incomplete. When using 'orient=columns' , pandas expects {k:[v]} dicts. So first convert the dict to this format, e.g. with `d = {k: [v] for k, v in mydict.items()}` and then do `pd.DataFrame.from_dict(data=d, orient='columns')` – Rabarberski Jul 05 '21 at 10:18
16

Easiest way is to ignore the csv module and format it yourself.

with open('my_file.csv', 'w') as f:
    [f.write('{0},{1}\n'.format(key, value)) for key, value in my_dict.items()]
Phil Horowitz
  • 185
  • 1
  • 2
7
outfile = open( 'dict.txt', 'w' )
for key, value in sorted( mydict.items() ):
    outfile.write( str(key) + '\t' + str(value) + '\n' )
FCAlive
  • 71
  • 1
  • 3
2

Can you just do:

for key in mydict.keys():
    f.write(str(key) + ":" + str(mydict[key]) + ",");

So that you can have

key_1: value_1, key_2: value_2

louis.luo
  • 2,921
  • 4
  • 28
  • 46
  • 3
    Better would be `','.join("%s:%s" % (k,v) for k,v in mydict.items())` - you are usually better off iterating over a dict's items, which gives you keys and values together, than over a dict's keys and doing 'n' value lookups. `','.join(...)` takes care of only putting commas between values, without adding the extra trailing comma. – PaulMcG Dec 31 '11 at 03:24
  • note that you won't need the semicolon at the end for this python code – beep_check Jan 11 '19 at 02:08
1

I've personally always found the csv module kind of annoying. I expect someone else will show you how to do this slickly with it, but my quick and dirty solution is:

with open('dict.csv', 'w') as f:  # This creates the file object for the context 
                                  # below it and closes the file automatically
    l = []
    for k, v in mydict.iteritems(): # Iterate over items returning key, value tuples
        l.append('%s: %s' % (str(k), str(v))) # Build a nice list of strings
    f.write(', '.join(l))                     # Join that list of strings and write out

However, if you want to read it back in, you'll need to do some irritating parsing, especially if it's all on one line. Here's an example using your proposed file format.

with open('dict.csv', 'r') as f: # Again temporary file for reading
    d = {}
    l = f.read().split(',')      # Split using commas
    for i in l:
        values = i.split(': ')   # Split using ': '
        d[values[0]] = values[1] # Any type conversion will need to happen here
Griffith Rees
  • 1,285
  • 2
  • 15
  • 24
-1
#code to insert and read dictionary element from csv file
import csv
n=input("Enter I to insert or S to read : ")
if n=="I":
    m=int(input("Enter the number of data you want to insert: "))
    mydict={}
    list=[]
    for i in range(m):
        keys=int(input("Enter id :"))
        list.append(keys)
        values=input("Enter Name :")
        mydict[keys]=values

    with open('File1.csv',"w") as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=list)
        writer.writeheader()
        writer.writerow(mydict)
        print("Data Inserted")
else:
    keys=input("Enter Id to Search :")
    Id=str(keys)
    with open('File1.csv',"r") as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            print(row[Id]) #print(row) to display all data
-2

Have you tried to add the "s" on: w.writerow(mydict) like this: w.writerows(mydict)? This issue happened to me but with lists, I was using singular instead of plural.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Hikhuj
  • 177
  • 1
  • 5