【问题标题】:A pickle with jsonpickle (Python 3.7)带有 jsonpickle 的泡菜(Python 3.7)
【发布时间】:2019-12-14 18:07:21
【问题描述】:

我在使用 jsonpickle 时遇到问题。相反,我相信它可以正常工作,但它没有产生我想要的输出。

我有一个名为“节点”的类。在“节点”中有四个整数(x、y、宽度、高度)和一个名为“NodeText”的 StringVar。

序列化 StringVar 的问题在于其中有很多信息,对我来说这不是必需的。我在程序运行时使用它,但不需要保存和加载它。

所以我使用了一种方法来更改 jsonpickle 保存的内容,对我的节点使用 __getstate__ 方法。这样我就可以做到:

    def __getstate__(self):
        state = self.__dict__.copy()
        del state['NodeText']
        return state

到目前为止,这运行良好,并且没有保存 NodeText。问题来了。我将文件正常加载到对象中(在本例中为节点列表)。

加载的问题是:从 json 加载的项目不是我班级中定义的节点。它们几乎相同(它们有 x、y、宽度和高度),但是因为 NodeText 没有保存在 json 文件中,所以这些类似 Node 的对象没有该属性。当我在这些节点的屏幕上创建可视实例时,这会导致错误,因为 StringVar 用于 tkinter Entry 文本变量。

我想知道是否有办法将这个“几乎节点”加载到我的实际节点中。我可以一次将每个属性复制到一个新实例中,但这似乎是一种不好的方法。

我还可以在保存之前将 NodeText StringVar 设为空(从而节省文件中的空间),然后在加载时重新初始化它。这意味着我将拥有完整的对象,但不知何故,这似乎是一个尴尬的解决方法。

如果您想知道 StringVar 还有多少信息,我的测试 json 文件只有两个节点。只需保存基本属性(x,y,width,height),文件为1k。每个都有一个 StringVar,这就变成了 8k。在小幅增加的情况下,我不会太在意,但这非常大。

我可以强制加载到这个 Node 类型,而不仅仅是 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
    }
  }
}

由于类名在那里,我假设它是类的实例化。但是当您使用 jsonpickle 加载文件时,您会获得字典并可以检查加载的数据并检查每个节点。两个节点都不包含属性“NodeText”。也就是说,它不是以 'None' 为值的东西 - 属性 simple 不存在。

【问题讨论】:

    标签: json python-3.x jsonpickle


    【解决方案1】:

    那是因为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}}
    

    【讨论】:

      猜你喜欢
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 2017-11-09
      • 2013-09-22
      • 1970-01-01
      相关资源
      最近更新 更多