【问题标题】:What is the best way to Serialize/Deserialize Class Objects in Python?在 Python 中序列化/反序列化类对象的最佳方法是什么?
【发布时间】:2021-10-24 21:49:56
【问题描述】:

我正在尝试从我正在使用的单元中记录一些数据,以进行长期和短期的数据收集和存储。

我应该使用 json 库还是 pickle 库,然后如何从文件中加载单位的数据,能够对其进行操作、添加单位等,然后将更新的数据保存回文件?

以下是对我的问题以及卡在哪里的详细说明:

对于每个单元,我在类对象中都有一些数据:

unit_1.name = 'unit_1'
unit_1.folder = 'C:\\Users\\Thomas\\Documents\\1'
unit_1.serial_number = 1
unit_1.offsets = [0.00, 0.00, 0.00, 0.00 ...]
unit_1.status = 'Open'
etc

我想将这些对象存储为长期存储(所以在文件中),但我还需要能够通过执行以下操作从命令行将它们作为类对象访问:

>python
Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

>from file import unit_log
>unit_log.load()
>unit_1.serial_number
1

我想创建这样的新单位:

>unit_2 = unit_log(2)

这将在类的 init 模块中创建其他字段。 之后,我可以通过执行以下操作来保存我创建或修改的单元:

>unit_log.save()

它会将所有单位保存到文件中。这是该类的代码:

file.py

class unit_log:
    def __init__ (self, serial_number):
        self.serial_number = serial_number;
        self.unit_name = 'unit_'+str(serial_number)
        self.status = 'Open';
        self.offsets = [];
        self.folder = 'C:\\Users\\Thomas\\Documents\\' + str(serial_number)
    @classmethod
    def load (self):
        #Something that loads the data
    @classmethod
    def save (self):
        #Something that saves the data

我目前的理解是,我正在尝试做的事情称为序列化/反序列化,并且有几种不同的方法可以做到这一点(主要是 pickle 库和 json 库)。

我的问题是:如何将 json 文件(或 pickle 文件)反序列化为一堆类对象? 我假设 json 文件看起来像这样:

unit_logs.json
{
    unit_1:{
    {
    "unit_name": "unit_1",
    "serial_number": 1,
    "status": "Open",
    "offsets": [],
    "folder": "C:\\Users\\Thomas\\Documents\\1"
    }
    unit_2...
    unit_3...
    ...
}

我会使用log = json.load(unit_logs.json) 加载文件。我想然后有一个

for unit in log:
    unit["unit_name"] = unit_log(unit)

但这不是声明变量的方式。

我相信 pickle 库的工作方式类似,但我对那个库不太熟悉。

我应该使用 json 库还是 pickle 库,然后如何从文件中加载单位的数据,能够对其进行操作、添加单位等,然后将更新的数据保存回文件?

【问题讨论】:

  • 为什么要用pickle?你的 json 看起来很简单,使用 json 比 pickle 更快
  • 我刚读到泡菜是另一种选择。我宁愿使用json,因为我对此了解更多,只是不知道如何将json文件反序列化为如上所述的类对象。

标签: python json serialization deserialization pickle


【解决方案1】:

如果你想使用 json,试试这个:

json.dumps(unit_log_instance.__dict__)

【讨论】:

  • 您能否详细说明如何在上面的代码中实现这一点?什么是 unit_log_instance?这也没有回答如何一次创建每个单元的类对象的问题。
【解决方案2】:

pickle库好用

将对象obj 转储到文件中:

import pickle

with open(f_path, "wb") as f:
    pickle.dump(obj, f)

加载一个pickle文件:

with open(f_path, "rb") as f:
    obj = pickle.load(f)

然后你可以更改obj并再次写入文件

如果您想多次加载同一个泡菜文件并拥有不同的对象,您可以:

N=<number of copies>

with open(f_path, "rb") as f:
    obj_list = [pickle.load(f) for _ in range(N)]

现在您可以分别编辑obj_list 中的每个对象,如果您想将其状态保存到pickle 文件,请使用pickle.dump,如上所述。

因此,您可以从“模板”pickle 文件加载,然后根据需要编辑对象。

【讨论】:

  • 这并没有回答如何在加载模块中同时写入所有单元的问题
  • 什么意思?您的序列化对象也可以是对象列表
  • 如果我正确理解了您的代码,那么 'obj' 将是所有单位。我将如何去改变一个单位?我在想,当你反序列化这些单元时,它们会以某种方式都有自己的变量,这样你就可以按照“>unit_1.open_folder()”或“unit_2.log_data()”的方式做一些事情。如果它们都没有自己的变量名,你还能如何编写和操作某些单元?
  • 我已经阅读了更多内容,也许答案是为每个单元创建动态变量?不过不太确定这在实践中是如何工作的。
  • 每次从 pickle 文件加载时,都会得到一个全新的不同对象,因此您可以拥有一个对象数组或将您的对象放入其他集合中。在答案中添加了这一点。
【解决方案3】:

这里有一些你可能有用的东西。有一个 Python 包可用于从 YAML/JSON/dicts 巧妙地构造对象,并且正在积极开发和扩展。 (完全披露,我是这个包的合著者,见here

编辑

现在,在您的情况下,您可以考虑按如下方式使用它:

作为 YAML 文件 (filename.yaml)(或 JSON),可以定义以下内容:

name: 'unit_1'
folder: 'C:\\Users\\Thomas\\Documents\\1'
serial_number: 1
offsets: [0.00, 0.00, 0.00, 0.00 ]
status: 'Open'

实现了从文件中将其作为 Python 对象加载:

>> python
Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

> from pickle_rick import PickleRick
> unit_1 = PickleRick('./filename.yaml')
> unit_1.serial_number
1

然后可以进行更改并再次保存到文件中:

> unit_1.serial_number += 41
> unit_1.serial_number
42
> unit_1.to_yaml_file('./filename.yaml')

或作为 JSON 文件。

现在,要拥有多个单元,请考虑如下结构:

units:
    - name: 'unit_1'
      folder: 'C:\\Users\\Thomas\\Documents\\1'
      serial_number: 1
      offsets: [0.00, 0.00, 0.00, 0.00 ]
      status: 'Open'

    - name: 'unit_2'
      folder: 'C:\\Users\\Thomas\\Documents\\1'
      serial_number: 1
      offsets: [0.00, 0.00 ]
      status: 'Closed'

然后可以将其作为单元列表加载:

>> python
Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

> from pickle_rick import PickleRick
> all_units = PickleRick('./filename.yaml', deep=True)
> all_units.units[0].serial_number
1

原帖

安装:

pip install pickle-rick

用途:

定义一个 YAML 或 JSON 字符串(或文件)。

BASIC:
 text: test
 dictionary:
   one: 1
   two: 2
 number: 2
 list:
   - one
   - two
   - four
   - name: John
     age: 20
 USERNAME:
   type: env
   load: USERNAME
 callable_lambda:
   type: lambda
   load: "lambda: print('hell world!')"
 datenow:
   type: lambda
   import:
     - "from datetime import datetime as dd"
   load: "lambda: print(dd.utcnow().strftime('%Y-%m-%d'))"
 test_function:
   type: function
   name: test_function
   args:
     x: 7
     y: null
     s: hello world
     any:
       - 1
       - hello
   import:
     - "math"
   load: >
     def test(x, y, s, any):
       print(math.e)
       iii = 111
       print(iii)
       print(x,s)
       if y:
         print(type(y))
       else:
         print(y)
       for i in any:
         print(i)

然后将其用作对象。

>> from pickle_rick import PickleRick

>> config = PickleRick('./config.yaml', deep=True, load_lambda=True)

>> config.BASIC.dictionary
{'one' : 1, 'two' : 2}

>> config.BASIC.callable_lambda()
hell world!

您可以定义 Python 函数,从其他文件或 REST API、环境变量加载其他数据,然后将所有内容再次写入 YAML 或 JSON。

这在构建需要结构化配置文件的系统或在笔记本中作为交互式结构时特别有效。

使用它有一个安全注意事项。只加载受信任的文件,因为任何代码都可以执行,因此不要在不知道完整内容的情况下加载任何内容。

该软件包名为 PickleRick,可在此处获得:

【讨论】:

  • 您能否调整它以至少远程匹配问题设置?虽然对于 OP 想要做的事情来说,这似乎是一个可行的 后端,但它似乎也需要与 OP 已经发现的其他后端一样多的样板。
猜你喜欢
  • 2011-09-23
  • 2021-01-06
  • 1970-01-01
  • 2010-09-27
  • 1970-01-01
  • 2012-03-31
  • 2015-01-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多