132

I have a dictionary and am trying to write it to a file.

exDict = {1:1, 2:2, 3:3}
with open('file.txt', 'r') as file:
    file.write(exDict)

I then have the error

file.write(exDict)
TypeError: must be str, not dict

So I fixed that error but another error came

exDict = {111:111, 222:222}
with open('file.txt', 'r') as file:
    file.write(str(exDict))

The error:

file.write(str(exDict))
io.UnsupportedOperation: not writable

I have no idea what to do as I am still a beginner at python. If anyone knows how to resolve the issue, please provide an answer.

NOTE: I am using python 3, not python 2

talex
  • 16,886
  • 2
  • 27
  • 60
Nic
  • 1,389
  • 2
  • 12
  • 13

10 Answers10

198

First of all you are opening file in read mode and trying to write into it. Consult - IO modes python

Secondly, you can only write a string to a file. If you want to write a dictionary object, you either need to convert it into string or serialize it.

import json

# as requested in comment
exDict = {'exDict': exDict}

with open('file.txt', 'w') as file:
     file.write(json.dumps(exDict)) # use `json.loads` to do the reverse

In case of serialization

import cPickle as pickle

with open('file.txt', 'w') as file:
     file.write(pickle.dumps(exDict)) # use `pickle.loads` to do the reverse

For python 3.x pickle package import would be different

import _pickle as pickle
hspandher
  • 14,790
  • 2
  • 28
  • 43
  • 1
    That worked! Although, it only writes the content of the dictionary. Can you get it to write: exDict = {111:111, 222:222} – Nic May 01 '16 at 10:28
  • I thought of that but thought there was a better way. It works though so thank you! – Nic May 01 '16 at 10:35
  • If you are not too attached with `=` sign, the edit I have made might do the job. – hspandher May 01 '16 at 10:38
  • The way you had it before: file.write('exDict = ' + json.dumps(exDict)) worked fine for me as I am using it right now. – Nic May 01 '16 at 10:50
  • @hspandher How do you read back `file.write(json.dumps(exDict))`? `json.load(file)` doesn't work on this. – quil Aug 06 '17 at 14:14
  • @verity Try `json.loads` instead of `json.load`. – hspandher Aug 06 '17 at 15:58
  • Why would you use `json.dumps(exDict)` over seemingly more straight-forward `str(exDict)`? – Jan Kukacka Jan 19 '18 at 12:02
  • 1
    @JanKukacka JSON is a standard data format. What `str(exDict)` would produce won't always be a valid JSON. One reason from the back of my head is that single quotes are not valid in a JSON file, while might be present when we use `str` method. – hspandher Jan 19 '18 at 12:20
  • @hspandher I agree JSON has benefits when it comes to further machine processing of the dictionary contents (and then pickle sound even better than JSON), but OP only asked how to print it into a text file. Also note that JSON serialization has some unexpected troubles with decimals: https://stackoverflow.com/questions/1960516/python-json-serialize-a-decimal-object – Jan Kukacka Jan 19 '18 at 15:19
  • Python 3 requires explicit binary output with pickle (`with open('file.txt', 'wb') as file:`) – Moilleadóir Oct 03 '20 at 07:41
  • why not use `json.dump(exDict, file)` instead of `dumps` ? – baxx Jan 07 '21 at 14:34
  • when pickling to file, one can do it directly `with open('fname.pickle', 'wb') as file: pickle.dump(exDict, file)` no need for `file.write()` which actually gives you an error. – Daniel Kislyuk Jan 22 '21 at 09:10
77

I do it like this in python 3:

with open('myfile.txt', 'w') as f:
    print(mydictionary, file=f)
NKSHELL
  • 919
  • 7
  • 8
  • 5
    I like this one because there is no import necessary. The answer further above data.write(str(dictionary)) will not work with a correct dictionary as it will just write in your file – Si Mon Dec 11 '18 at 14:38
  • 1
    One thing I am also curious is why not just do print(mydictionary, file=open('myfile.txt', 'w')) – MadmanLee May 06 '19 at 20:45
  • 1
    @MadmanLee I think both are OK, and its a matter of how we prefer our code looks like. – NKSHELL May 07 '19 at 04:26
  • 3
    with open('myfile.txt', 'r') as f: content = f.read(); dic = eval(content); – NKSHELL Sep 02 '19 at 06:24
  • The reason why json is better than just writing `str(mydict)` to a file is precisely that you don't need to `eval` the contents to get the `dict` object back. `eval` is a security rosk and shouldn't be used if there are better options available. – snakecharmerb Apr 30 '20 at 10:47
  • @snakecharmerb I think eval is safe in this particular case. And even if it's not, python is general purpose and security is not concerned, e.g. in research programming. – NKSHELL May 04 '20 at 20:30
  • @MadmanLee, You should use a with-statement, because than you close the file. You wouldn't close the file in your example. – Chris Fowl Jun 15 '20 at 18:25
29
fout = "/your/outfile/here.txt"
fo = open(fout, "w")

for k, v in yourDictionary.items():
    fo.write(str(k) + ' >>> '+ str(v) + '\n\n')

fo.close()
MaNKuR
  • 2,362
  • 1
  • 18
  • 29
Sange Negru
  • 307
  • 3
  • 2
  • 14
    Code-only answers are discouraged because they do not explain how they resolve the issue. Please update your answer to explain how this improves on the other accepted and upvoted answers this question already has. Please review [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). – FluffyKitten Sep 10 '17 at 07:59
  • 1
    Also, you should use the `with` statement when reading from and writing to files: https://stackoverflow.com/questions/3012488/what-is-the-python-with-statement-designed-for – Falko Jan 15 '18 at 17:58
18

The probelm with your first code block was that you were opening the file as 'r' even though you wanted to write to it using 'w'

with open('/Users/your/path/foo','w') as data:
    data.write(str(dictionary))
Erty Seidohl
  • 4,197
  • 3
  • 30
  • 43
clyde_the_frog
  • 189
  • 1
  • 2
  • this is the correct answer, since the code within the question has an error. – Ricardo Rivaldo Nov 29 '18 at 02:21
  • When I try the json route, I get a fail because I have some "NaN" values in floats. There is no fix without damaging the data itself if you want to write JSON. Hence, this answer is the preferred one because it can save a text file to accurately reflect the dict. – pauljohn32 May 29 '20 at 17:43
10

If you want a dictionary you can import from a file by name, and also that adds entries that are nicely sorted, and contains strings you want to preserve, you can try this:

data = {'A': 'a', 'B': 'b', }

with open('file.py','w') as file:
    file.write("dictionary_name = { \n")
    for k in sorted (data.keys()):
        file.write("'%s':'%s', \n" % (k, data[k]))
    file.write("}")

Then to import:

from file import dictionary_name
MarMat
  • 608
  • 5
  • 12
6

For list comprehension lovers, this will write all the key : value pairs in new lines in dog.txt

my_dict = {'foo': [1,2], 'bar':[3,4]}

# create list of strings
list_of_strings = [ f'{key} : {my_dict[key]}' for key in my_dict ]

# write string one by one adding newline
with open('dog.txt', 'w') as my_file:
    [ my_file.write(f'{st}\n') for st in list_of_strings ]
DavideL
  • 252
  • 1
  • 3
  • 12
2

I know this is an old question but I also thought to share a solution that doesn't involve json. I don't personally quite like json because it doesn't allow to easily append data. If your starting point is a dictionary, you could first convert it to a dataframe and then append it to your txt file:

import pandas as pd
one_line_dict = exDict = {1:1, 2:2, 3:3}
df = pd.DataFrame.from_dict([one_line_dict])
df.to_csv('file.txt', header=False, index=True, mode='a')

I hope this could help.

Angelo
  • 1,182
  • 2
  • 14
  • 30
1
exDict = {1:1, 2:2, 3:3}
with open('file.txt', 'w+') as file:
    file.write(str(exDict))
ianzo
  • 11
  • 1
0

You can do as follow :

import json
exDict = {1:1, 2:2, 3:3}
file.write(json.dumps(exDict))

https://developer.rhino3d.com/guides/rhinopython/python-xml-json/

LaSul
  • 1,972
  • 1
  • 17
  • 35
-2
import json

with open('tokenler.json', 'w') as file:
     file.write(json.dumps(mydict, ensure_ascii=False))
Mehmet Ali Bayram
  • 5,904
  • 2
  • 20
  • 25