在Python中向类添加保存功能的一般方法
我最近突然想到,使用某种形式的元编程来替换持久化所需的(公认是有限的)样板代码,然后使用pickle加载对象。所以你会得到这样的结果在Python中向类添加保存功能的一般方法,python,metaprogramming,pickle,metaclass,Python,Metaprogramming,Pickle,Metaclass,我最近突然想到,使用某种形式的元编程来替换持久化所需的(公认是有限的)样板代码,然后使用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_som
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__方法变得复杂,因为会发生以下情况:
#!/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()))
这可能适合@aIKid,我不知道codereview.stackexchange.com。我不知道哪个网站更合适,但这似乎对我来说是一个没有意义的问题,因为到目前为止,我还没有找到一种非版主在网站之间移动内容的方法。我会问“为什么使用元类?”这里。似乎常规子类化可以完成这项工作。我正在使用元类来拦截对实际类的uuu init_uu_u方法的调用,并说,“如果文件路径上有一个文件,只需加载它,而不是执行常规的uuu init_u_u_u_u_u。”我不想要求在使用此功能的每个类中都必须重新生成该逻辑。因为这样做的结果不太好,所以把这个问题贴在这里。我想我可以说,使用sync_pickle特性的类不能有一个_init__方法,而是应该提供一个方法,如果SyncPickle在filepath中找不到文件,它将调用该方法。这是最好的方法吗?可以创建实例而不调用它们的
\uuuuu init\uuuuuu()
:尝试SomeClass.\uuuuu new\uuuuuuuu(SomeClass)
。