用 jsonpickle 泡菜 (Python 3.7)
A pickle with jsonpickle (Python 3.7)
我在使用 jsonpickle 时遇到问题。相反,我认为它可以正常工作,但没有产生我想要的输出。
我有一个叫 'Node' 的 class。在 'Node' 中有四个整数(x、y、宽度、高度)和一个名为 'NodeText'.
的 StringVar
序列化 StringVar 的问题在于其中有很多信息,而对我来说这只是没有必要。我在程序 运行 时使用它,但不需要保存和加载它。
所以我使用一种方法来更改 jsonpickle 保存的内容,使用我的节点的 __getstate__
方法。这样我就可以做到:
def __getstate__(self):
state = self.__dict__.copy()
del state['NodeText']
return state
到目前为止效果很好,NodeText 没有保存。问题来自负载。我像往常一样将文件加载到一个对象中(在本例中是一个节点列表)。
加载的问题是这样的:从json加载的项目不是我class中定义的节点。它们几乎相同(它们有 x、y、宽度和高度)但是因为 NodeText 没有保存在 json 文件中,所以这些类似节点的对象没有 属性。当我在这些节点的屏幕上创建可视实例时,这会导致错误,因为 StringVar 用于 tkinter Entry 文本变量。
我想知道是否有办法将此 'almost node' 加载到我的实际节点中。我可以一次将每个 属性 复制到一个新实例中,但这似乎是一种糟糕的方法。
我还可以在保存之前将 NodeText StringVar 清空(从而将 space 保存在文件中),然后在加载时重新初始化它。这意味着我将拥有完整的对象,但不知何故这似乎是一个尴尬的解决方法。
如果您想知道 StringVar 还有多少信息,我的测试 json 文件只有两个节点。只保存基本属性(x,y,width,height),文件为1k。每个都有一个 StringVar,这就变成了 8k。如果是小幅度的增加,我不会太在意,但这已经是相当大的了。
我可以强制加载此节点类型,而不仅仅是 Python 创建的某些新类型吗?
编辑:如果您想知道 json 是什么样子,请看这里:
{
"1": {
"py/object": "Node.Node",
"py/state": {
"ImageLocation": "",
"TextBackup": "",
"height": 200,
"uID": 1,
"width": 200,
"xPos": 150,
"yPos": 150
}
},
"2": {
"py/object": "Node.Node",
"py/state": {
"ImageLocation": "",
"TextBackup": "",
"height": 200,
"uID": 2,
"width": 100,
"xPos": 50,
"yPos": 450
}
}
}
因为 class 名称在那里,我假设它是 class 的实例化。但是当你使用 jsonpickle 加载文件时,你会得到字典并可以检查加载的数据并检查每个节点。两个节点都不包含 属性 'NodeText'。也就是说,它不是以 'None' 作为值的东西 - 属性 simple 不存在。
那是因为jsonpickle
正常情况下不知道你的对象中有哪些字段,它只恢复状态传过来的字段而状态没有字段NodeText
属性 .所以它只是错过了它:)
您可以添加一个 __setstate__
魔术方法来在您恢复的对象中实现 属性。这样你就可以处理有或没有 属性.
的转储
def __setstate__(self, state):
state.setdefault('NodeText', None)
for k, v in state.items():
setattr(self, k, v)
一个小例子
from pprint import pprint, pformat
import jsonpickle
class Node:
def __init__(self) -> None:
super().__init__()
self.NodeText = Node
self.ImageLocation = None
self.TextBackup = None
self.height = None
self.uID = None
self.width = None
self.xPos = None
self.yPos = None
def __setstate__(self, state):
state.setdefault('NodeText', None)
for k, v in state.items():
setattr(self, k, v)
def __getstate__(self):
state = self.__dict__.copy()
del state['NodeText']
return state
def __repr__(self) -> str:
return str(self.__dict__)
obj1 = Node()
obj1.NodeText = 'Some heavy description text'
obj1.ImageLocation = 'test ImageLocation'
obj1.TextBackup = 'test TextBackup'
obj1.height = 200
obj1.uID = 1
obj1.width = 200
obj1.xPos = 150
obj1.yPos = 150
print('Dumping ...')
dumped = jsonpickle.encode({1: obj1})
print(dumped)
print('Restoring object ...')
print(jsonpickle.decode(dumped))
产出
# > python test.py
Dumping ...
{"1": {"py/object": "__main__.Node", "py/state": {"ImageLocation": "test ImageLocation", "TextBackup": "test TextBackup", "height": 200, "uID": 1, "width": 200, "xPos": 150, "yPos": 150}}}
Restoring object ...
{'1': {'ImageLocation': 'test ImageLocation', 'TextBackup': 'test TextBackup', 'height': 200, 'uID': 1, 'width': 200, 'xPos': 150, 'yPos': 150, 'NodeText': None}}
我在使用 jsonpickle 时遇到问题。相反,我认为它可以正常工作,但没有产生我想要的输出。
我有一个叫 'Node' 的 class。在 'Node' 中有四个整数(x、y、宽度、高度)和一个名为 'NodeText'.
的 StringVar序列化 StringVar 的问题在于其中有很多信息,而对我来说这只是没有必要。我在程序 运行 时使用它,但不需要保存和加载它。
所以我使用一种方法来更改 jsonpickle 保存的内容,使用我的节点的 __getstate__
方法。这样我就可以做到:
def __getstate__(self):
state = self.__dict__.copy()
del state['NodeText']
return state
到目前为止效果很好,NodeText 没有保存。问题来自负载。我像往常一样将文件加载到一个对象中(在本例中是一个节点列表)。
加载的问题是这样的:从json加载的项目不是我class中定义的节点。它们几乎相同(它们有 x、y、宽度和高度)但是因为 NodeText 没有保存在 json 文件中,所以这些类似节点的对象没有 属性。当我在这些节点的屏幕上创建可视实例时,这会导致错误,因为 StringVar 用于 tkinter Entry 文本变量。
我想知道是否有办法将此 'almost node' 加载到我的实际节点中。我可以一次将每个 属性 复制到一个新实例中,但这似乎是一种糟糕的方法。
我还可以在保存之前将 NodeText StringVar 清空(从而将 space 保存在文件中),然后在加载时重新初始化它。这意味着我将拥有完整的对象,但不知何故这似乎是一个尴尬的解决方法。
如果您想知道 StringVar 还有多少信息,我的测试 json 文件只有两个节点。只保存基本属性(x,y,width,height),文件为1k。每个都有一个 StringVar,这就变成了 8k。如果是小幅度的增加,我不会太在意,但这已经是相当大的了。
我可以强制加载此节点类型,而不仅仅是 Python 创建的某些新类型吗?
编辑:如果您想知道 json 是什么样子,请看这里:
{
"1": {
"py/object": "Node.Node",
"py/state": {
"ImageLocation": "",
"TextBackup": "",
"height": 200,
"uID": 1,
"width": 200,
"xPos": 150,
"yPos": 150
}
},
"2": {
"py/object": "Node.Node",
"py/state": {
"ImageLocation": "",
"TextBackup": "",
"height": 200,
"uID": 2,
"width": 100,
"xPos": 50,
"yPos": 450
}
}
}
因为 class 名称在那里,我假设它是 class 的实例化。但是当你使用 jsonpickle 加载文件时,你会得到字典并可以检查加载的数据并检查每个节点。两个节点都不包含 属性 'NodeText'。也就是说,它不是以 'None' 作为值的东西 - 属性 simple 不存在。
那是因为jsonpickle
正常情况下不知道你的对象中有哪些字段,它只恢复状态传过来的字段而状态没有字段NodeText
属性 .所以它只是错过了它:)
您可以添加一个 __setstate__
魔术方法来在您恢复的对象中实现 属性。这样你就可以处理有或没有 属性.
def __setstate__(self, state):
state.setdefault('NodeText', None)
for k, v in state.items():
setattr(self, k, v)
一个小例子
from pprint import pprint, pformat
import jsonpickle
class Node:
def __init__(self) -> None:
super().__init__()
self.NodeText = Node
self.ImageLocation = None
self.TextBackup = None
self.height = None
self.uID = None
self.width = None
self.xPos = None
self.yPos = None
def __setstate__(self, state):
state.setdefault('NodeText', None)
for k, v in state.items():
setattr(self, k, v)
def __getstate__(self):
state = self.__dict__.copy()
del state['NodeText']
return state
def __repr__(self) -> str:
return str(self.__dict__)
obj1 = Node()
obj1.NodeText = 'Some heavy description text'
obj1.ImageLocation = 'test ImageLocation'
obj1.TextBackup = 'test TextBackup'
obj1.height = 200
obj1.uID = 1
obj1.width = 200
obj1.xPos = 150
obj1.yPos = 150
print('Dumping ...')
dumped = jsonpickle.encode({1: obj1})
print(dumped)
print('Restoring object ...')
print(jsonpickle.decode(dumped))
产出
# > python test.py
Dumping ...
{"1": {"py/object": "__main__.Node", "py/state": {"ImageLocation": "test ImageLocation", "TextBackup": "test TextBackup", "height": 200, "uID": 1, "width": 200, "xPos": 150, "yPos": 150}}}
Restoring object ...
{'1': {'ImageLocation': 'test ImageLocation', 'TextBackup': 'test TextBackup', 'height': 200, 'uID': 1, 'width': 200, 'xPos': 150, 'yPos': 150, 'NodeText': None}}