📜  Python-Json 5 : python自定义class进行Json格式化

📅  最后修改于: 2020-09-01 07:21:47             🧑  作者: Mango

以前的章节中,我们介绍了Python 的内置json模块只能处理Python基本数据类型,即将Python基本数据类型进行Json序列化

当您尝试编码定制Python对象成JSON格式,您收到一个类型错误:Object of type SampleClass is not JSON serializable

因此,我们将在此介绍如何将任意Python对象序列化为JSON,以便您可以将任何自定义Python对象转换为JSON格式的数据。

大致介绍四种方法

  • 自定义JSON编码器将对象序列化为Json
  • 自定义toJSON()方法将对象序列化为Json
  • 使用jsonpickle使对象序列化为Json
  • 继承dict使对象序列化为Json

1、自定义JSONEncoder进行JSON格式化

Python json模块具有JSONEncoder类。如果您想要更丰富的自定义输出,则可以扩展它。即您将继承JSONEncoder子类,以便可以实现自定义JSON序列化。

JSON模块的json.dump和json.jumps方法有一个clskwarg。使用此参数,您可以传递自定义JSON编码器,该编码器告诉json.dump()json.dumps()方法如何将您的对象编码为JSON格式的数据。默认的JSONEncoder类具有一个default()在执行时将使用的方法JSONEncoder.encode(object)。此方法仅将基本类型转换为JSON。

您的自定义JSONEncoder子类将覆盖该default()方法以序列化其他类型。用clskwarg in json.dumps()方法指定它;否则,将使用默认的JSONEncoder。

import json
from json import JSONEncoder

class Employee:
    def __init__(self, name, salary, address):
        self.name = name
        self.salary = salary
        self.address = address

class Address:
    def __init__(self, city, street, pin):
        self.city = city
        self.street = street
        self.pin = pin

# subclass JSONEncoder
class EmployeeEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__

address = Address("Alpharetta", "7258 Spring Street", "30004")
employee = Employee("John", 9000, address)

print("Printing to check how it will look like")
print(EmployeeEncoder().encode(employee))

print("Encode Employee Object into JSON formatted Data using custom JSONEncoder")
employeeJSONData = json.dumps(employee, indent=4, cls=EmployeeEncoder)
print(employeeJSONData)

# Let's load it using the load method to check if we can decode it or not.
print("Decode JSON formatted Data")
employeeJSON = json.loads(employeeJSONData)
print(employeeJSON)

现在我们查看输出结果:

Printing to check how it will look like
{"name": "John", "salary": 9000, "address": {"city": "Alpharetta", "street": "7258 Spring Street", "pin": "30004"}}

Encode Object into JSON formatted Data using custom JSONEncoder
{
    "name": "John",
    "salary": 9000,
    "address": {
        "city": "Alpharetta",
        "street": "7258 Spring Street",
        "pin": "30004"
    }
}

Decode JSON formatted Data
{'name': 'John', 'salary': 9000, 'address': {'city': 'Alpharetta', 'street': '7258 Spring Street', 'pin': '30004'}}

值得注意

  • EmployeeEncoder类重写了类的default()方法JSONEncoder,因此我们能够将自定义Python对象转换为JSON。
  • 在EmployeeEncoder类中,我们将Object转换为Python字典格式。

注意:如果您还想将JSON解码回Custom Python对象,请参考将JSON解码到Custom Python 对象,而不是解码为字典

2、使用toJSON()方法使JSON类可序列化

一个简单直接的解决方案,我们还可以在该类中实现序列化器方法,从而不需要编写自定义JSONEncoder

import json

class Employee:
    def __init__(self, name, salary, address):
        self.name = name
        self.salary = salary
        self.address = address

    def toJson(self):
        return json.dumps(self, default=lambda o: o.__dict__)

class Address:
    def __init__(self, city, street, pin):
        self.city = city
        self.street = street
        self.pin = pin

address = Address("Alpharetta", "7258 Spring Street", "30004")
employee = Employee("John", 9000, address)

print("Encode into JSON formatted Data")
employeeJSONData = json.dumps(employee.toJson(), indent=4)
print(employeeJSONData)

# Let's load it using the load method to check if we can decode it or not.
print("Decode JSON formatted Data")
employeeJSON = json.loads(employeeJSONData)
print(employeeJSON)

此时的输出结果如下:

Encode into JSON formatted Data
"{\"name\": \"John\", \"salary\": 9000, \"address\": {\"city\": \"Alpharetta\", \"street\": \"7258 Spring Street\", \"pin\": \"30004\"}}"

Decode JSON formatted Data
{"name": "John", "salary": 9000, "address": {"city": "Alpharetta", "street": "7258 Spring Street", "pin": "30004"}}

注意事项

  • 正如代码所示,能够将Employee对象编码和解码为JSON格式的流。
  • 在调用toJson的函数中,我们使用json.jumps()的default参数先转换其他类型数据到字典,然后再序列化为Json数据。

注意:如果您还想将JSON解码回Custom Python对象,请参考将JSON解码到Custom Python对象,而不是字典。

3、使用jsonpickle模块进行JSON序列化

jsonpickle是一个Python库,目的是与复杂的Python对象一起使用完成复杂的功能。您可以使用jsonpickle将复杂的Python对象序列化为JSON。反之,也可以从JSON反序列化到复杂的Python对象。

如您所知,Python 的内置json模块只能处理Python原语类型(例如,字典,列表,字符串,数字,None等), jsonpickle建立在这些库之上,并允许将更复杂的数据结构序列化为JSON。

主要步骤

  • 使用安装jsonpickle pip install jsonpickle
  • 执行jsonpickle.encode(object)
import json
import jsonpickle
from json import JSONEncoder

class Employee(object):
    def __init__(self, name, salary, address):
        self.name = name
        self.salary = salary
        self.address = address

class Address(object):
    def __init__(self, city, street, pin):
        self.city = city
        self.street = street
        self.pin = pin

address = Address("Alpharetta", "7258 Spring Street", "30004")
employee = Employee("John", 9000, address)

print("Encode Object into JSON formatted Data using jsonpickle")
empJSON = jsonpickle.encode(employee, unpicklable=False)

print("Writing JSON Encode data into Python String")
employeeJSONData = json.dumps(empJSON, indent=4)
print(employeeJSONData)

print("Decode JSON formatted Data using jsonpickle")
EmployeeJSON = jsonpickle.decode(employeeJSONData)
print(EmployeeJSON)

# Let's load it using the load method to check if we can decode it or not.
print("Load JSON using loads() method")
employeeJSON = json.loads(EmployeeJSON)
print(employeeJSON)

输出如下:

Encode Object into JSON formatted Data using jsonpickle
Writing JSON Encode data into Python String
"{\"address\": {\"city\": \"Alpharetta\", \"pin\": \"30004\", \"street\": \"7258 Spring Street\"}, \"name\": \"John\", \"salary\": 9000}"

Decode JSON formatted Data using jsonpickle
{"address": {"city": "Alpharetta", "pin": "30004", "street": "7258 Spring Street"}, "name": "John", "salary": 9000}

Load JSON using loads() method
{'address': {'city': 'Alpharetta', 'pin': '30004', 'street': '7258 Spring Street'}, 'name': 'John', 'salary': 9000}

注意事项

unpicklable=False那么些数据解码回Object。如果希望将JSON解码回Employee Object,需设置unpicklable=True

4、继承Dict使类对象序列化为Json

如果不想编写自定义编码器,也不想使用jsonpickle,则可以使用这种解决方案。如果您的class不复杂,则此解决方案有效。对于复杂的类/对象,您将必须显式设置一些keys。

import json

class Employee(dict):
    def __init__(self, name, age, salary, address):
        dict.__init__(self, name=name, age=age, salary=salary, address=address)

class Address(dict):
    def __init__(self, city, street, pin):
        dict.__init__(self, city=city, street=street, pin=pin)

address = Address("Alpharetta", "7258 Spring Street", "30004")
employee = Employee("John", 36, 9000, address)

print("Encode into JSON formatted Data")
employeeJSON = json.dumps(employee)
print(employeeJSON)

# Let's load it using the load method to check if we can decode it or not.
print("Decode JSON formatted Data")
employeeJSONData = json.loads(employeeJSON)
print(employeeJSONData)

输出如下:

Encode into JSON formatted Data
{"name": "John", "age": 36, "salary": 9000, "address": {"city": "Alpharetta", "street": "7258 Spring Street", "pin": "30004"}}

Decode JSON formatted Data
{'name': 'John', 'age': 36, 'salary': 9000, 'address': {'city': 'Alpharetta', 'street': '7258 Spring Street', 'pin': '30004'}}

此方法对于不愿意修改json.dumps(obj)小伙伴是很有用 即您只需按json.dumps(obj)原样调用

——>>>>>该节内容到此结束了,希望提供的四种方法能对小伙伴们提供帮助