📜  在 Python-JSON 中编码和解码自定义对象

📅  最后修改于: 2022-05-13 01:55:03.296000             🧑  作者: Mango

在 Python-JSON 中编码和解码自定义对象

我们知道JSON代表JavaScript Object Notation 。它是一种轻量级的数据交换格式,已成为最流行的网络数据交换媒介。它受欢迎的原因在于它既易于人类阅读,又易于机器解析和生成。此外,它是最广泛使用的 REST API 格式。

注意:有关详细信息,请参阅使用Python读取、写入和解析 JSON

入门

Python提供了一个内置的json库来处理 JSON 对象。您只需在Python程序中使用以下行导入 JSON 模块并开始使用其功能。

import json

现在 JSON 模块提供了很多功能,我们将只讨论其中的两种方法。它们是转储装载。将Python对象转换为 json 对象的过程称为JSON 序列化编码,相反的过程,即将 json 对象转换为Python对象称为反序列化或解码

对于编码,我们使用json.dumps() ,对于解码,我们将使用json.loads() 。因此很明显,dumps 方法会将Python对象转换为序列化的 JSON字符串,而 loading 方法将从序列化的 JSON字符串中解析Python对象。

笔记:

  • 这里值得一提的是,在序列化过程中创建的 JSON 对象只是一个Python字符串,这就是为什么您会发现本文中的术语“JSON 对象”和“JSON字符串”可以互换使用
  • 同样重要的是要注意 JSON 对象对应于Python中的 Dictionary 。因此,当您使用加载方法时,默认返回Python字典(除非您按照本文自定义解码部分中的讨论更改此行为)

例子:

import json
  
# A basic python dictionary
py_object = {"c": 0, "b": 0, "a": 0} 
  
# Encoding
json_string = json.dumps(py_object)
print(json_string)
print(type(json_string))
  
# Decoding JSON
py_obj = json.loads(json_string) 
print()
print(py_obj)
print(type(py_obj))

输出:

{"c": 0, "b": 0, "a": 0}


{'c': 0, 'b': 0, 'a': 0}

虽然我们在上面看到的是一个非常简单的例子。但是你有没有想过在自定义对象的情况下会发生什么?在这种情况下,上面的代码将不起作用,我们将收到类似的错误 - TypeError: Object of type SampleClass is not JSON serializable 。那么该怎么办?不用担心,我们将进入以下部分。

编码和解码自定义对象

在这种情况下,我们需要付出更多的努力来让它们序列化。让我们看看如何做到这一点。假设我们有一个用户定义的类Student ,我们想让它成为 JSON 可序列化的。最简单的方法是在我们的类中定义一个方法,该方法将提供我们类实例的 JSON 版本。

例子:

import json
   
class Student:
    def __init__(self, name, roll_no, address):
        self.name = name
        self.roll_no = roll_no
        self.address = address
   
    def to_json(self):
        '''
        convert the instance of this class to json
        '''
        return json.dumps(self, indent = 4, default=lambda o: o.__dict__)
   
class Address:
    def __init__(self, city, street, pin):
        self.city = city
        self.street = street
        self.pin = pin
          
address = Address("Bulandshahr", "Adarsh Nagar", "203001")
student = Student("Raju", 53, address)
  
# Encoding
student_json = student.to_json()
print(student_json)
print(type(student_json))
  
# Decoding
student = json.loads(student_json)
print(student)
print(type(student))

输出:

实现此目的的另一种方法是创建一个扩展JSONEncoder的新类,然后将该类用作dumps方法的参数。

例子:

import json
from json import JSONEncoder
  
class Student:
    def __init__(self, name, roll_no, address):
        self.name = name
        self.roll_no = roll_no
        self.address = address
  
  
class Address:
    def __init__(self, city, street, pin):
        self.city = city
        self.street = street
        self.pin = pin
  
class EncodeStudent(JSONEncoder):
        def default(self, o):
            return o.__dict__
              
address = Address("Bulandshahr", "Adarsh Nagar", "203001")
student = Student("Raju", 53, address)
  
# Encoding custom object to json
# using cls(class) argument of
# dumps method
student_JSON = json.dumps(student, indent = 4,
                          cls = EncodeStudent)
print(student_JSON)
print(type(student_JSON))
  
# Decoding
student = json.loads(student_JSON)
print()
print(student)
print(type(student))

输出:

对于自定义解码,如果我们想将 JSON 转换为其他Python对象(即不是默认字典),有一种非常简单的方法是使用load方法的object_hook参数。我们需要做的就是定义一个方法,该方法将定义我们希望如何处理数据,然后将该方法作为 object_hook 参数发送到加载方法,请参见给定代码。此外,load 的返回类型将不再是Python字典。无论我们作为object_hook 传入的方法的返回类型是什么,它也将成为loads 方法的返回类型。这意味着在以下示例中,复数将是返回类型。

import json
  
  
def as_complex(dct):
      
    if '__complex__' in dct:
        return complex(dct['real'], dct['imag'])
      
    return dct
  
res = json.loads('{"__complex__": true, "real": 1, "imag": 2}',
           object_hook = as_complex)
print(res)
print(type(res))

输出:

(1+2j)