使Python类JSON可序列化---Object of type SampleClass is not JSON serializable

你在这里是因为当您尝试编码定制Python对象成JSON格式,您收到一个类型错误Object of type SampleClass is not JSON serializable。在本文中,我将向您展示如何将任意Python对象序列化为JSON,以便您可以将任何自定义Python对象转换为JSON格式的数据。

Python的内置json模块只能处理具有直接JSON等效项的Python基本类型。即,根本的问题是JSON编码器json.dump()和 json.dumps() 仅知道默认情况下如何序列化基本对象类型集(例如,字典,列表,字符串,数字,None等)。

为了解决这个问题,我们需要构建一个自定义编码器以使我们的Class JSON可序列化。

有多种方法可以使Python类JSON可序列化。您可以选择最适合您的问题复杂性的一种。让我们一一理解。

本课程的目标

  • 编写自己的自定义JSON编码器以使JSON类可序列化
  • 创建自定义toJSON()方法以使Python类JSON可序列化
  • 使用jsonpickle 模块使JSON序列化
  • 如何从继承类dict以使类JSON可序列化

一、编写自定义JSONEncoder以使类JSON可序列化

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

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

您的自定义JSONEncoder子类将覆盖该default()方法以序列化其他类型。用clskwarg injson.dumps()方法指定它;否则,将使用默认的JSONEncoder。范例:json.dumps(cls=CustomEncoder)。让我们现在来看示例。

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 Object而不是字典中。

 

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

一个简单直接的解决方案。除了使JSON类可序列化之外,我们还可以在该类中实现序列化器方法
因此,我们不需要编写自定义JSONEncoder

这个新的toJSON()序列化器方法将返回Object的JSON表示形式。即,它将自定义Python对象转换为JSON string。让我们来看一个例子。

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格式的流。
  • 我们使用method的usedefault参数json.dumps()将其他类型序列化为dict并将新创建的dict转换为JSON字符串。

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

另外,尝试解决我们的Python JSON练习

 

三、使用jsonpickle模块使JSON序列化

jsonpickle是一个Python库,旨在与复杂的Python对象一起使用。您可以使用jsonpickle将复杂的Python对象序列化为JSON。此外,还有从JSON反序列化到复杂的Python对象。

如您所知,Python的内置json模块只能处理具有直接JSON等效项的Python原语类型(例如,字典,列表,字符串,数字,无等)。

jsonpickle建立在这些库之上,并允许将更复杂的数据结构序列化为JSON。jsonpickle具有高度的可配置性和可扩展性,允许用户选择JSON后端并添加其他后端。

步骤

  • 使用安装jsonpickle pip install jsonpickle
  • 执行jsonpickle.encode(object)以序列化自定义Python对象。

您可以参考Jsonpickle文档以获取更多详细信息。让我们看一下使一个Python类JSON可序列化的jsonpickle示例。

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。或请参阅直接将JSON数据加载到Object中。我提到了如何使用jsonpickle将JSON数据直接加载到Object中。

另外,您可以尝试使用jsons模块使JSON类可序列化。

 

四、从dict继承以使类JSON可序列化

如果您不想编写自定义编码器,也不想使用jsonpickle,则可以使用此解决方案。检查此解决方案是否适合您。如果您的班级不复杂,则此解决方案有效。对于棘手的事情,您将必须显式设置密钥。

对于无法修改其json.dumps(obj)调用以包含自定义编码器的用户,此方法很有用 即,如果您想按json.dumps(obj)原样调用,那么一个简单的解决方案就是从dict继承

因此,在这种情况下,您无需将呼叫更改为json.dumps()。我的意思是,如果您要传递对象并且JSON转储发生在您无法控制修改json.dumps()调用的不同应用程序组件或框架内,该怎么办。

让我们看一下演示

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'}}

原作者:

About Vishal

Founder of PYnative.com I am a Python developer and I love to write articles to help developers. Follow me on Twitter. All the best for your future Python endeavors!

英文原文链接:https://pynative.com/make-python-class-json-serializable/

感谢原作者的无私分享

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值