Python 酸洗不可涂刷的物体
我正在用pygame制作一个绘图程序,我想给用户一个选项,保存程序的精确状态,然后在以后重新加载。 在这一点上,我保存了我的globalsdict的一个副本,然后迭代,对每个对象进行酸洗。pygame中的某些对象无法进行pickle,但可以转换为字符串并以这种方式进行pickle。我的代码就是这样设置的,但其中一些不可拼接的对象是通过引用访问的。换句话说,它们不在全局字典中,但被全局字典中的对象引用。我想在这个递归中对它们进行pickle,但我不知道如何告诉pickle返回它遇到问题的对象,更改它,然后再次尝试pickle。我的代码真的很混乱,如果有一种不同的、更好的方法来做我想做的事情,请告诉我Python 酸洗不可涂刷的物体,python,pygame,pickle,save,savestate,Python,Pygame,Pickle,Save,Savestate,我正在用pygame制作一个绘图程序,我想给用户一个选项,保存程序的精确状态,然后在以后重新加载。 在这一点上,我保存了我的globalsdict的一个副本,然后迭代,对每个对象进行酸洗。pygame中的某些对象无法进行pickle,但可以转换为字符串并以这种方式进行pickle。我的代码就是这样设置的,但其中一些不可拼接的对象是通过引用访问的。换句话说,它们不在全局字典中,但被全局字典中的对象引用。我想在这个递归中对它们进行pickle,但我不知道如何告诉pickle返回它遇到问题的对象,更改
surfaceStringHeader = 'PYGAME.SURFACE_CONVERTED:'
imageToStringFormat = 'RGBA'
def save_project(filename=None):
assert filename != None, "Please specify path of project file"
pickler = pickle.Pickler(file(filename,'w'))
for key, value in globals().copy().iteritems():
#There's a bit of a kludge statement here since I don't know how to
#access module type object directly
if type(value) not in [type(sys),type(None)] and \
key not in ['__name__','value','key'] and \
(key,value) not in pygame.__dict__.iteritems() and \
(key,value) not in sys.__dict__.iteritems() and \
(key,value) not in pickle.__dict__.iteritems():
#Perhaps I should add something to the above to reduce redundancy of
#saving the program defaults?
#Refromat unusable objects:
if type(value)==pygame.Surface:
valueString = pygame.image.tostring(value,imageToStringFormat)
widthString = str(value.get_size()[0]).zfill(5)
heightString = str(value.get_size()[1]).zfill(5)
formattedValue = surfaceStringHeader+widthString+heightString+valueString
else:
formattedValue = value
try:
pickler.dump((key,formattedValue))
except Exception as e:
print key+':' + str(e)
def open_project(filename=None):
assert filename != None, "Please specify path to project file"
unpickler = pickle.Unpickler(file(filename,'r'))
haventReachedEOF = False
while haventReachedEOF:
try:
key,value = unpickler.load()
#Rework the unpicklable objects stored
if type(value) == str and value[0:25]==surfaceStringHeader:
value = pygame.image.frombuffer(value[36:],(int(value[26:31]),int(value[31:36])),imageToStringFormat)
sys.modules['__main__'].__setattr__(key,value)
except EOFError:
haventReachedEOF = True
简言之:不要这样做
对应用程序中的所有内容进行酸洗会造成混乱,并可能导致问题。从程序中获取所需的数据,并手动将其存储在适当的数据格式中,然后通过从该数据中创建所需的内容来加载数据。从您的评论中,您尝试做的最困难的部分似乎是为用户提供一个实时解释器,并保存该解释器的状态 那么,作为子进程运行实时解释器怎么样?要将对象模型中的任何信息公开给脚本,都可以显式地公开(无论是通过
多处理
共享内存还是某种消息传递API)
然后,您不需要保存自己的解释器的完整状态,这要么非常困难,要么不可能;以正常方式保存数据模型,然后可以从外部而不是内部冻结子解释器
这显然比你想做的要复杂得多,但我不认为任何简单的事情都能奏效。例如,如果用户有一个带代码的实时解释器,他们可以修补任何东西,甚至是酸洗代码,然后会发生什么?您需要定义一些关于可以保存和恢复哪些内容的限制,如果这些限制足够广泛,我认为您必须从外部执行
同时,正如一篇评论中提到的,
scipy
(或Enthound附带的一些相关项目)和ipython
都具有针对有限用例的保存和恢复功能,这至少为您提供了一些可供研究的代码,但是它们的用例可能与您的不一样。如果您知道所有不可点击的对象类型,那么这个问题答案中的代码可能会有所帮助“”--我写这篇文章是为了回应类似的情况,我知道所有不可点击的对象类型,但我不知道它们在数据结构中的位置。您可以使用此代码查找它们,用其他代码替换它们,然后在取消勾选时使用类似的代码将它们放回。您希望保存整个程序的状态,以便以后可以重新加载。这是一个完美的Pickle用例,我看不出这个用例有任何问题。然而,您清除globals()名称空间并过滤掉sys、pygame和pickle的方法是不可靠的。通常的模式是使用一个会话对象进行pickle
此外,我认为可能会对如何泡菜产生一些困惑:
session = None
import pickle
def startsession():
globals session
session = pickle.Unpickler(sessionfilehandle('r')).load()
if session is None: session = Session()
def savesession(filename=None):
globals session
pickle.Pickler.dump(session,sessionfilehandle('w'))
class Session(object):
def __init__(self):
self.someobject=NewObject1()
#.... plus whole object tree representing the whole game
self.somedevicehandlethatcannotbepickled=GetDeviceHandle1() #for example
def __getstate__(self):
odict = self.__dict__.copy()
del odict['somedevicehandlethatcannotbepickled'] #don't pickle this
return odict
def __setstate__(self, dict):
self.__dict__.update(dict)
self.somedevicehandlethatcannotbepickled=GetDeviceHandle1()
为此,我使用,它可以序列化python中的几乎所有内容。Dill还可以帮助您理解代码失败时是什么导致酸洗失败。此外,这也是对测试套件的一个非常方便的补充
>>> import dill
>>> # blah blah blah... your session code here
>>> dill.dump_session('pygame.pkl')
>>>
>>> # and if you get a pickling error, use dill's tools to discover a workaround
>>> dill.detect.badobjects(your_bad_object, depth=1)
>>>
>>> # visualize the references in your bad objects
>>> objgraph.show_refs(your_bad_object, filename='pygame_bad_object.png')
这辆车看起来很笨重。明确你想要保存的价值观,这样你就不会有很多麻烦了。根据经验,我可以说,精确定义程序的状态是一项前期工作,但它鼓励更好的设计,并迫使您仔细考虑自己的状态(这在调试时很方便)。问题的难点在于,程序的状态包括为用户运行实时解释器,可用于修改图形的状态。你在最初的问题中没有提到这一点。该程序与一个实时解释器一起运行,允许用户重写或添加函数和数据结构。我希望在加载项目时保留并重新定义这些变量,因此我不能将pickle限制为预定义变量。没有办法保存python程序的状态吗?@hedgehogrider:在任何情况下都无法保存python程序的完整状态。无论是
ipython
还是scipy
对这个想法的实现都非常有限,超出了pickle
(就此而言,多处理将pickle
扩展到了库存之外),因此您可能需要向他们寻求想法。但是,您是否需要用户能够(例如)将monkeypatch作为您框架的一部分并使其可恢复?您的建议并不是一项简单的任务。这是否可能超出了我的知识范围,但你可能想问问自己,这真的需要有这么多的空间。顺便说一句,我不知道