我最近想到了使用某种形式的元编程来替换持久化然后使用pickle加载对象所需的(不可否认的限制)样板代码。所以你会得到像
这样的东西class MyClass(object):
# Something to add save-ability (maybe a decorator or metaclass)...
# More code...
my_instance = MyClass('/path/to/persistent_file')
my_instance.do_some_stuff()
my_instance.save()
my_instance._do_some_more_stuff()
my_instance.save()
我试图通过使用元类来实现这一目标。不幸的是,它并没有像我希望的那样好。 __init__方法变得复杂,因为发生了这种情况:
MyClass .__ init __能够从#3告诉#1基本上是我实施中的黑客攻击。有没有一种干净的方法(无论是使用元类,装饰器还是其他)?
编辑:@roippi问,“听起来你正试图重新实现搁置,不是吗?”是的,这个练习开始是为了重新实现搁置,但允许任意键,这基本上是我的SyncPickleDict。然后我发现自己想要概括它。我修复了这个例子,使用非字符串键来使它更清晰。#!/usr/bin/python2.7
import pickle
import os
import datetime
from collections import OrderedDict
class SyncPickleParent(object):
def __init__ (self, filepath, *args, **kwargs):
print "here and self is", self
self.__filepath = filepath
super(SyncPickleParent, self).__init__(*args, **kwargs)
def sync_pickle(self):
with open(self.__filepath, "w") as ofile:
pickle.dump(self, ofile)
class SyncPickle(type):
def __new__(meta, name, bases, dct):
return super(SyncPickle, meta).__new__(meta, name, (SyncPickleParent,)+bases, dct)
def __call__(cls, filepath, force_init=False, force_overwrite=False, *args, **kwds):
if force_init:
return type.__call__(cls, filepath, *args, **kwds)
if not force_overwrite:
try:
with open(filepath) as ifile:
red = pickle.load(ifile)
red._SyncPickleParent__filepath = filepath
return red
except IOError as ioe:
pass
result = type.__call__(cls, filepath, *args, **kwds)
result.sync_pickle() # Check that file is writable
return result
class SyncPickleDict(OrderedDict):
__metaclass__ = SyncPickle
def __init__(self, *args, **kwargs):
print "in init; args={}; kwargs={}".format(args, kwargs)
super(SyncPickleDict, self).__init__(*args, **kwargs)
def __reduce__(self):
# Yuck. The tuple output by __reduce__ has to have two bogus
# arguments
return (self.__class__, ("dummy", True, False, tuple(self.items())))
if "__main__" == __name__:
spd = SyncPickleDict(os.path.expanduser("~/tmp/bar.dat"))
spd[(1,2,3)] = 'foobar'
spd['access_count'] = spd.get('access_count', 0) + 1
spd[datetime.datetime.now()] = "A new key every time"
spd.sync_pickle()
print "\n".join(map(str, spd.iteritems()))