你在这里是因为当您尝试编码定制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()方法有一个cls
kwarg。使用此参数,您可以传递自定义JSON编码器,该编码器告诉json.dump()
或json.dumps()
方法如何将您的对象编码为JSON格式的数据。默认的JSONEncoder类具有一个default()
在执行时将使用的方法JSONEncoder.encode(object)
。此方法仅将基本类型转换为JSON。
您的自定义JSONEncoder子类将覆盖该default()
方法以序列化其他类型。用cls
kwarg 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的use
default
参数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/
感谢原作者的无私分享!