12

I've had a search around but can't find anything regarding this...

I'm looking for a way to save a dictionary to file and then later be able to load it back into a variable at a later date by reading the file.

The contents of the file don't have to be "human readable" it can be as messy as it wants.

Thanks - Hyflex

EDIT

import cPickle as pickle

BDICT = {}

## Automatically generated START
name = "BOB"
name_title = name.title()
count = 5
BDICT[name_title] = count

name = "TOM"
name_title = name.title()
count = 5
BDICT[name_title] = count

name = "TIMMY JOE"
name_title = name.title()
count = 5
BDICT[name_title] = count
## Automatically generated END

if BDICT:
    with open('DICT_ITEMS.txt', 'wb') as dict_items_save:
        pickle.dump(BDICT, dict_items_save)

BDICT = {} ## Wiping the dictionary

## Usually in a loop
firstrunDICT = True

if firstrunDICT:
    with open('DICT_ITEMS.txt', 'rb') as dict_items_open:
        dict_items_read = dict_items_open.read()
        if dict_items_read:
            BDICT = pickle.load(dict_items_open)
            firstrunDICT = False
            print BDICT

Error:

Traceback (most recent call last):
  File "C:\test3.py", line 35, in <module>
    BDICT = pickle.load(dict_items_open)
EOFError
Ryflex
  • 5,559
  • 25
  • 79
  • 148
  • Can you include the lines around `BTS_DICT`? You've already loaded the pickled object with `BDICT` and then you try to do it again -- is BTS_DICT outside your context-manager (`with open()...`)? – Justin Carroll Jun 26 '13 at 19:05

5 Answers5

24

A few people have recommended shelve - I haven't used it, and I'm not knocking it. I have used pickle/cPickle and I'll offer the following approach:

How to use Pickle/cPickle (the abridged version)...

There are many reasons why you would use Pickle (or its noticable faster variant, cPickle). Put tersely Pickle is a way to store objects outside of your process.

Pickle not only gives you the options to store objects outside your python process, but also does so in a serialized fashion. Meaning, First In, First Out behavior (FIFO).

import pickle

## I am making up a dictionary here to show you how this works...
## Because I want to store this outside of this single run, it could be that this
## dictionary is dynamic and user based - so persistance beyond this run has
## meaning for me.  
myMadeUpDictionary = {"one": "banana", "two": "banana", "three": "banana", "four": "no-more"}

with open("mySavedDict.txt", "wb") as myFile:
    pickle.dump(myMadeUpDictionary, myFile)

So what just happened?

  • Step1: imported a module named 'pickle'
  • Step2: created my dictionary object
  • Step3: used a context manager to handle the opening/closing of a new file...
  • Step4: dump() the contents of the dictionary (which is referenced as 'pickling' the object) and then write it to a file (mySavedDict.txt).

If you then go into the file that was just created (located now on your filesystem), you can see the contents. It's messy - ugly - and not very insightlful.

nammer@crunchyQA:~/workspace/SandBox/POSTS/Pickle & cPickle$ cat mySavedDict.txt 
(dp0
S'four'
p1
S'no-more'
p2
sS'three'
p3
S'banana'
p4
sS'two'
p5
g4
sS'one'
p6
g4
s.

So what's next?

To bring that BACK into our program we simply do the following:

import pickle

with open("mySavedDict.txt", "rb") as myFile:
    myNewPulledInDictionary = pickle.load(myFile)

print myNewPulledInDictionary

Which provides the following return:

{'four': 'no-more', 'one': 'banana', 'three': 'banana', 'two': 'banana'}

cPickle vs Pickle

You won't see many people use pickle these days - I can't think off the top of my head why you would want to use the first implementation of pickle, especially when there is cPickle which does the same thing (more or less) but a lot faster!

So you can be lazy and do:

import cPickle as pickle

Which is great if you have something already built that uses pickle... but I argue that this is a bad recommendation and I fully expect to get scolded for even recommending that! (you should really look at your old implementation that used the original pickle and see if you need to change anything to follow cPickle patterns; if you have legacy code or production code you are working with, this saves you time refactoring (finding/replacing all instances of pickle with cPickle).

Otherwise, just:

import cPickle

and everywhere you see a reference to the pickle library, just replace accordingly. They have the same load() and dump() method.

Warning Warning I don't want to write this post any longer than it is, but I seem to have this painful memory of not making a distinction between load() and loads(), and dump() and dumps(). Damn... that was stupid of me! The short answer is that load()/dump() does it to a file-like object, wheres loads()/dumps() will perform similar behavior but to a string-like object (read more about it in the API, here).

Again, I haven't used shelve, but if it works for you (or others) - then yay!

RESPONSE TO YOUR EDIT

You need to remove the dict_items_read = dict_items_open.read() from your context-manager at the end. The file is already open and read in. You don't read it in like you would a text file to pull out strings... it's storing pickled python objects. It's not meant for eyes! It's meant for load().

Your code modified... works just fine for me (copy/paste and run the code below and see if it works). Notice near the bottom I've removed your read() of the file object.

import cPickle as pickle

BDICT = {}

## Automatically generated START
name = "BOB"
name_title = name.title()
count = 5
BDICT[name_title] = count

name = "TOM"
name_title = name.title()
count = 5
BDICT[name_title] = count

name = "TIMMY JOE"
name_title = name.title()
count = 5
BDICT[name_title] = count
## Automatically generated END

if BDICT:
    with open('DICT_ITEMS.txt', 'wb') as dict_items_save:
        pickle.dump(BDICT, dict_items_save)

BDICT = {} ## Wiping the dictionary

## Usually in a loop
firstrunDICT = True

if firstrunDICT:
    with open('DICT_ITEMS.txt', 'rb') as dict_items_open:
        BDICT = pickle.load(dict_items_open)
        firstrunDICT = False
        print BDICT
Justin Carroll
  • 1,362
  • 1
  • 13
  • 37
  • I've re-edited my main topic for an example of my code which makes the error... how can I fix it? – Ryflex Jun 26 '13 at 20:08
  • see above "Response to your Edit" and remember to select the answer that best solves your problem. (put a green checkmark next to the header of the answer that best answers your question). – Justin Carroll Jun 26 '13 at 20:24
  • @Hyflex, nice catch. Mea culpa. I made edits on SO without testing in Python. I have edited the bad line out (removed the truthiness of `dict_items_read` so it never evaluates. I copied/pasted this code and it tested good. – Justin Carroll Jun 27 '13 at 01:59
  • 3
    However, for Python 3+, use just `pickle` : https://stackoverflow.com/a/37138791/2306662 (I agree about the 2.7 tag, but this is for other people who end up here while searching for Python 3+ answers in specific) – nikpod Aug 04 '17 at 11:01
5

Python has the shelve module for this. It can store many objects in a file that can be opened up later and read in as objects, but it's operating system-dependent.

import shelve

dict1 = #dictionary
dict2 = #dictionary

#flags: 
#   c = create new shelf; this can't overwrite an old one, so delete the old one first
#   r = read
#   w = write; you can append to an old shelf
shelf = shelve.open("filename", flag="c")
shelf['key1'] = dict1
shelf['key2'] = dict2

shelf.close()

#reading:
shelf = shelve.open("filename", flag='r')
for key in shelf.keys():
    newdict = shelf[key]
    #do something with it

shelf.close()
xgord
  • 4,606
  • 6
  • 30
  • 51
3

You can also use Pickle for this task. Here's a blog post that explains how to do it.

tatsuhirosatou
  • 25,149
  • 14
  • 39
  • 40
  • 1
    `pickle` is the perfect tool for this job. I'd only recommend to import `cPickle as pickle` for orders-of-magnitude better performance (and equal feature set), and to pass `pickle.HIGHEST_PROTOCOL` to dump. (It defaults to an old 7-bit protocol to ensure forward compatibility.) – user4815162342 Jun 26 '13 at 14:16
  • agreed. With that said, I haven't used shelve, but I immediately thought of cPickle for this job. To the OP: FYI worth a quick read (http://stackoverflow.com/questions/8514020/marshal-dumps-faster-cpickle-loads-faster). – Justin Carroll Jun 26 '13 at 16:01
  • @Nascent_Notes If you see my first post in this question I've edited to show an example bit of code and an error I am getting :/ Any ideas anyone? – Ryflex Jun 26 '13 at 17:15
  • @Hyflex, are you loading a previously 'pickled' object? You can't just read in any old thing you throw into a file. You need to build your object and then pickle it to a file, then you can load it back in. Can you pastbin your code so I can see more of what you are doing? – Justin Carroll Jun 26 '13 at 17:54
  • @Nascent_Notes I pickled the dictionary in a different file and the picked files contents is: `(dp0 S'Bob' p1 I2 sS'Tom' p2 I2 sS'Jimmy' p3 I3 s.` – Ryflex Jun 26 '13 at 18:56
  • @Hyflex, see my most recent post and follow that as a rough guide to see if you can reimplement what you have done to fix the problem, if not, I'd need to see more of your code to help (otherwise I'd be guessing). – Justin Carroll Jun 26 '13 at 19:00
2

What you are looking for is shelve.

madjar
  • 12,691
  • 2
  • 44
  • 52
  • I assume this is the dictionary equivalent to the pickle lib for lists? – Ryflex Jun 26 '13 at 14:07
  • @Hyflex not really. `pickle` words for dicts too. It is a serialization library that works on any python object. Shelve is just a convenient layer above pickle, especially when storing many object. Pickle might be enough in you case, but there's no harm in using shelve. – madjar Jun 27 '13 at 08:58
  • 1
    Can you elaborate? -1 until there's more of a description than a single link. – spacetyper Nov 30 '17 at 15:43
2

Two functions which create a text file for saving a dictionary and loading a dictionary (which was already saved before) for use again.

import pickle

def SaveDictionary(dictionary,File):
    with open(File, "wb") as myFile:
        pickle.dump(dictionary, myFile)
        myFile.close()

def LoadDictionary(File):
    with open(File, "rb") as myFile:
        dict = pickle.load(myFile)
        myFile.close()
        return dict

These functions can be called through :

SaveDictionary(mylib.Members,"members.txt") # saved dict. in a file
members = LoadDictionary("members.txt")     # opened dict. of members