I\'m trying to make an object act like a built-in list, except that its value be saved once modified.
The implementation I come up with is wrapping a
Here's an answer that's a lot like @unutbu's, but more general. It gives you a function you can call to sync your object to disk, and it works with other pickle-able classes besides list.
with pickle_wrap(os.path.expanduser("~/Desktop/simple_list"), list) as (lst, lst_sync):
lst.append("spam")
lst_sync()
lst.append("ham")
print(str(lst))
# lst is synced one last time by __exit__
Here's the code that makes that possible:
import contextlib, pickle, os, warnings
def touch_new(filepath):
"Will fail if file already exists, or if relevant directories don't already exist"
# http://stackoverflow.com/a/1348073/2829764
os.close(os.open(filepath, os.O_WRONLY | os.O_CREAT | os.O_EXCL))
@contextlib.contextmanager
def pickle_wrap(filepath, make_new, check_type=True):
"Context manager that loads a file using pickle and then dumps it back out in __exit__"
try:
with open(filepath, "rb") as ifile:
result = pickle.load(ifile)
if check_type:
new_instance = make_new()
if new_instance.__class__ != result.__class__:
# We don't even allow one class to be a subclass of the other
raise TypeError(("Class {} of loaded file does not match class {} of "
+ "value returned by make_new()")
.format(result.__class__, new_instance.__class__))
except IOError:
touch_new(filepath)
result = make_new()
try:
hash(result)
except TypeError:
pass
else:
warnings.warn("You probably don't want to use pickle_wrap on a hashable (and therefore likely immutable) type")
def sync():
print("pickle_wrap syncing")
with open(filepath, "wb") as ofile:
pickle.dump(result, ofile)
yield result, sync
sync()