Matteo
Matteo

Reputation: 8142

Pickle - Load variable if exists or create and save it

Is there a better way to load a variable with pickle if it already exists or create it and dump it if it doesn't?

if os.path.isfile("var.pickle"):
    foo = pickle.load( open( "var.pickle", "rb" ) )
else:
    foo = 3
    pickle.dump( foo, open( "var.pickle", "wb" ) )

Upvotes: 25

Views: 28685

Answers (2)

Aaron Hall
Aaron Hall

Reputation: 395633

I'd put it in a function for reusability, avoid error catching for control flow on the file, as it's less efficient, and I would use context managers to open the file.

import os
import pickle

def read_or_new_pickle(path, default):
    if os.path.isfile(path):
        with open(path, "rb") as f:
            try:
                return pickle.load(f)
            except Exception: # so many things could go wrong, can't be more specific.
                pass 
    with open(path, "wb") as f:
        pickle.dump(default, f)
    return default

usage:

foo = read_or_new_pickle(path="var.pickle", default=3)

foo returns 3

foo = read_or_new_pickle(path="var.pickle", default=4)

and foo still returns 3.

Admittedly, the following is rather short and elegant, but too many things could go wrong, and you'd have to catch everything (don't believe me? try this: import io, pickle; pickle.load(io.BytesIO(b"\x00")) and play with the binary):

import pickle

def read_or_new_pickle(path, default):
    try:
        foo = pickle.load(open(path, "rb"))
    except Exception:
        foo = default
        pickle.dump(foo, open(path, "wb"))
    return foo

Same usage. But I'm concerned the file might not be closed fast enough to avoid an error on opening it the second time in the event of a empty or malformed file. So use the context manager:

import pickle

def read_or_new_pickle(path, default):
    try:
        with open(path, "rb") as f:
            foo = pickle.load(f)
    except Exception:
        foo = default
        with open(path, "wb") as f:
            pickle.dump(foo, f)
    return foo

Upvotes: 9

alecxe
alecxe

Reputation: 474131

You can follow the EAFP principle and ask for forgiveness:

import pickle

try:
    foo = pickle.load(open("var.pickle", "rb"))
except (OSError, IOError) as e:
    foo = 3
    pickle.dump(foo, open("var.pickle", "wb"))

Upvotes: 44

Related Questions