在将应用程序从 python 2 转换为 python 3 时,我遇到了最奇怪的错误。 简而言之,该应用程序使用 wxPython 创建一个界面,用户可以在其中在画布上绘制不同的对象,并且当单击对象时,用户可以编辑它们并设置不同的参数。关闭应用程序时可以保存所有这些编辑。此保存是使用 python 的搁置库执行的。
这个应用程序与 python 2 完美配合,但是出于兼容性原因,我试图将其引入 python 3,但问题来了:在 python 3 上,我可以保存所有可能的对象,但是,如果我添加一个特定的对象,由图标组成的只是两个图标之间的一条线,我无法重新打开该项目。我可以添加对象、使用它、更改其设置、保存文件,但我无法重新打开它。
最大的问题是我没有调用堆栈来分析。它只是说它正在尝试解开架子上的物体,我得到的下一个信息是:
File "\Unpickle.py", line 25, in renamed_load
return RenameUnpickler(file_obj, encoding=encoding).load()
TypeError: Rect(): arguments did not match any overloaded call:
overload 1: too many arguments
overload 2: not enough arguments
overload 3: argument 1 has unexpected type 'float'
overload 4: argument 1 has unexpected type 'float'
overload 5: argument 1 has unexpected type 'float'
overload 6: argument 1 has unexpected type 'float'
真正奇怪的是,如果我打开一个在 python 2 中生成的文件(使用与this非常相似的东西进行转换,我不会收到相同的错误,我可以打开并编辑该文件。但是问题仍然存在当文件关闭并再次重新打开时出现。
这是执行读取的类,它继承自 Unpickler,以便我可以重写 find_class 方法。这个错误的最大问题,真正让我发疯的是,调用堆栈没有告诉我在 unpickle 过程中错误在哪里,并且如果我扫描代码中是否出现 Rect,我找不到任何错误。
class RenameUnpickler(pickle.Unpickler):
def find_class(self, module, name):
renamed_module = module
if module == "wx._gdi":
renamed_module = "wx"
return super(RenameUnpickler, self).find_class(renamed_module, name)
def renamed_load(file_obj, encoding):
return RenameUnpickler(file_obj, encoding=encoding).load()
def renamed_loads(pickled_bytes):
file_obj = io.BytesIO(pickled_bytes)
return renamed_load(file_obj)
class ShelfFileVO( shelve.DbfilenameShelf ):
def __init__(self, *args, **kwds):
kwds[ 'protocol' ] = 2
shelve.DbfilenameShelf.__init__( self, *args, **kwds )
self._semaphore = threading.BoundedSemaphore( 1 )
self.find_globals = None
def keys(self):
return [ k.decode() for k in self.dict.keys() ]
def has_key(self, key):
return key.encode() in self.dict
def __contains__(self, key):
return key.encode() in self.dict
def get(self, key, default=None):
#key = key.encode()
if key in self.dict:
return self[ key ]
else:
return default
def __getitem__(self, key):
#key = key.encode()
if key in list(self.cache.keys()):
value = self.cache[ key ]
else:
f = BytesIO( self.dict[ key ] )
value = renamed_load(f, encoding='latin1')
解决方案:我已经解决并发布了我的临时解决方案here并且它已在wxPython代码中得到纠正
过去在 Python 2/wxPython-old 中接受浮点数作为输入的所有 wxPython 原语(wx.Rect、wx.Size,还有很多其他)将不再适用于 Python 3/wxPython Phoenix。
您必须调整代码以将浮点数转换为整数,和/或腌制您的东西,以便使用整数参数保存矩形/大小。
如果您的应用程序中没有任何 wx.Rect/wx.Size 对象,您将必须确定您是否在腌制东西的任何地方调用 GetRect() 或 GetSize() 或 GetPosition() 。