Json
模块主要用来进行Python对象的序列化和反序列化。
该模块中常用的方法有以下四个:
json.dump
将Python对象序列化为Json格式的数据流并写入文件类型的对象中
json.dumps
将Python对象序列化为Json格式的字符串
json.load
从文件类型的对象中读取Json格式的数据并反序列化成Python对象
json.loads
将包含Json格式数据的字符串反序列化成Python对象
进行序列化时,Python类型与Json类型的转换关系如下表所示:
Python | Json |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float | number |
True | true |
False | false |
None | null |
进行反序列化时,Json类型与Python类型的转换关系如下:
Json | Python |
---|---|
object | dict |
array | list |
string | str |
number(int) | int |
number(real) | float |
true | True |
false | False |
null | None |
由于 json.dump
和 json.dumps
这两个方法、的作用与使用方法类似,故只对其中之一详细介绍。
同样地,json.load
和 json.loads
这两个方法的作用与使用方法类似,故也只对其中之一详细介绍。
该方法包含一个位置参数和多个仅限关键字参数,分别如下所示:
obj
要序列化的Python对象
skipkeys=False
是否跳过要序列化的对象中字典元素的key不是基本类型的数据;
如果为True
,则跳过,如果为False
,将抛出TypeError
异常。
>>> emp_info = {
'name': 'bob', b'age': 24} # 包含key为bytes类型的元素
>>> json.dumps(emp_info) # skipkeys参数为默认值False
Traceback (most recent call last):
File "" , line 1, in <module>
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
TypeError: keys must be str, int, float, bool or None, not bytes
>>> json.dumps(emp_info, skipkeys=True) # skipkeys参数设置为True时则可成功序列化
'{"name": "bob"}'
ensure_ascii=True
是否将要序列化的对象中的字符串中的非ascii字符进行转义。
如果该参数为True
,则将字符串中的非ascii字符转义成unicode字符串,否则,将不会进行转义。
>>> message = '我爱Python3'
>>> json.dumps(message) # ensure_ascii参数默认值为True,将会把非ascii字符转移成unicode字符串
'"\\u6211\\u7231Python3"'
>>> json.dumps(message, ensure_ascii=False) # ensure_ascii参数设置为False时,不会进行转义
'"我爱Python3"'
check_circular=True
是否进行容器类型的循环引用检查。
如果该参数设置为False
,则不进行检查,但是可能会引发OverflowError
或更严重的情况。
如果该参数设置为True
,则将进行容器类型的循环引用检查,并在发现循环引用时抛出异常。
>>> emp_dict = {
'id': 1, 'dept': 'sales'}
>>> emp_dict['info'] = emp_dict # 字典中包含循环引用
>>> json.dumps(emp_dict) # 默认进行循环引用的检查,将引发ValueError异常
Traceback (most recent call last):
File "" , line 1, in <module>
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
ValueError: Circular reference detected
>>> json.dumps(emp_dict, check_circular=False) # 设置为不进行循环引用的检查,但是在编码Json对象时仍然引发了异常
Traceback (most recent call last):
File "" , line 1, in <module>
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
RecursionError: maximum recursion depth exceeded while encoding a JSON object
allow_nan=True
是否允许序列化超出范围的float
类型的值(如float('inf')
、float('-inf')
、float('nan')
)。
如果该参数设置为True
,则上面列出的那些值将依次使用JavaScript中等价的值(Infinity
、-Infinity
、NaN
)来进 行替代;
如果该参数设置为False
,并且要序列化的对象中出现了那些超出范围的值,则将引发ValueError
异常。
>>> num_list = [2, 5, float('inf'), float('-inf'), float('nan')]
>>> json.dumps(num_list) # allow_nan的值默认为True,列表中后三个值将被替换为js中等价的值
'[2, 5, Infinity, -Infinity, NaN]'
>>> json.dumps(num_list, allow_nan=False) # allow_nan设置为False,引发ValueError异常
Traceback (most recent call last):
File "" , line 1, in <module>
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
ValueError: Out of range float values are not JSON compliant
indent=None
是否在数组元素和对象成员前增加缩进以便使格式更加美观。
如果该参数设置为大于等于1的整数,则添加换行符和对应数量的空格表示缩进,如果设置为0
,则表示只添加换行符,如果设置为None
,则表示无缩进。
>>> response = {
'status': 'success', 'code': 200, 'data': ['002', 'json', 5000]}
>>> print(json.dumps(response)) # 默认值None,不缩进
{
"status": "success", "code": 200, "data": ["002", "json", 5000]}
>>> print(json.dumps(response, indent=0)) # 设置为0,则只添加换行
{
"status": "success",
"code": 200,
"data": [
"002",
"json",
5000
]
}
>>> print(json.dumps(response, indent=4)) # 设置为4,添加换行和缩进
{
"status": "success",
"code": 200,
"data": [
"002",
"json",
5000
]
}
separators=None
设置Json中各项之间、对象的键和值之间的分隔符;
该参数必须是一个2元组,元组第一个元素表示Json数据中各项之间的分隔符,元组的第二个元素表示Json对象的键和值之间的分隔符。默认的分隔符为(’,’, ‘:’)
>>> response = {
'status': 'success', 'code': 200, 'data': ['002', 'json', 5000]}
>>> print(json.dumps(response, separators=(';', '!')))
>>> print(json.dumps(response, indent = 4, separators=(';', '!')))
{
"status"!"success";
"code"!200;
"data"![
"002";
"json";
5000
]
}
default=None
指定一个函数,用来将不可进行序列化的Python对象转化为可序列化的Python对象。
>>> json.dumps(b'hello world')
Traceback (most recent call last):
File "" , line 1, in <module>
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type bytes is not JSON serializable
>>> json.dumps(b'hello world', default=list)
'[104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]'
>>> json.dumps(b'hello world', default=str)
'"b\'hello world\'"'
sort_keys=False
是否要将对象中字典元素按照key进行排序。
默认为False
,即不进行排序,若指定为True
,则会进行排序。
>>> emp_info = {
'name': 'bob', 'age': 23, 'dept': 'sales', 'gender': 'male'}
>>> print(json.dumps(emp_info, indent = 4)) # 不按照key排序
{
"name": "bob",
"age": 23,
"dept": "sales",
"gender": "male"
}
>>> print(json.dumps(emp_info, indent = 4, sort_keys=True)) # 按照key进行排序
{
"age": 23,
"dept": "sales",
"gender": "male",
"name": "bob"
}
cls=None
指定一个定制的JSONEncoder
的子类(例如,重写了.default()
方法用来序列化附加的类型),指定该参数时请使用cls
关键字参数。如果未指定该参数,则将使用默认的JSONEncoder
。
>>> class IteratorEncoder(json.encoder.JSONEncoder):
... def default(self, o):
... try:
... iterable = iter(o)
... except TypeError:
... pass
... else:
... return list(iterable)
... return super().default(self, o)
...
>>> def get_nums(n):
... if not isinstance(n, int):
... raise TypeError('Expected int object')
... while n > 0:
... yield n
... n -= 1
...
>>> print(json.dumps(get_nums(10), indent=4, cls=IteratorEncoder))
[
10,
9,
8,
7,
6,
5,
4,
3,
2,
1
]
下面演示下该方法的简单用法:
>>> response = {
'status': 'success', 'code': 200, 'data': {
'username': 'bob', 'user_level': 6, 'nickname': 'playboy'}}
>>> with open('res.json', 'w', encoding='utf-8') as f:
... json.dump(response, f, indent=4)
...
>>> os.system('cat res.json')
{
"status": "success",
"code": 200,
"data": {
"username": "bob",
"user_level": 6,
"nickname": "playboy"
}
}0
>>>
该方法包含一个位置参数和多个仅限关键字参数,分别如下所示:
s
encoding=None
该参数已弃用,将会被忽略
cls=None
指定一个定制的JsonDecoder
子类,以便实现特定的反序列化需求;
object_hook=None
接受一个可调用对象,用于处理解码后生成的Python对象中dict
类型的值。
注意,这个处理过程是递归进行的,即返回的Python对象内部所有的字典结构都将被这个方法处理
>>> emp_info = {
'name': 'bob', 'age': 25, 'gender': 'Male'}
>>> def obj_hook(_dict):
... return list(_dict.items())
...
>>> json.loads(json.dumps(emp_info))
{
'name': 'bob', 'age': 25, 'gender': 'Male'}
>>> json.loads(json.dumps(emp_info), object_hook=obj_hook)
[('name', 'bob'), ('age', 25), ('gender', 'Male')]
>>> emp_list = [25, emp_info]
>>> emp_list
[25, {
'name': 'bob', 'age': 25, 'gender': 'Male'}]
>>> json.loads(json.dumps(emp_list),object_hook=obj_hook)
[25, [('name', 'bob'), ('age', 25), ('gender', 'Male')]]
>>> emp_d = [25, {
'name': 'bob', 'age': 25, 'gender': 'Male', 'emp_info': {
'count': 9, 'total_salary': 120000}}]
>>> json.loads(json.dumps(emp_d),object_hook=obj_hook)
[25, [('name', 'bob'), ('age', 25), ('gender', 'Male'), ('emp_info', [('count', 9), ('total_salary', 120000)])]]
parse_float=None
用于处理解码后的Python对象中的float
类型的值。
>>> json.loads('[23.5, 43.32, 5.934]', parse_float=lambda x: int(x)) # 将解码后的所有的float类型的值转成int类型
[23, 43, 5]
>>> json.loads('[23.5, 43.32, 5.934]', parse_float=lambda x: str(x)) # 将解码后的所有的float类型的值转成str类型
['23.5', '43.32', '5.934'] ```
parse_int=None
接受一个可调用对象,用于处理解码后的Python对象中的int
类型的值。
>>> json.loads('[23, 43, 5]', parse_int=lambda x: float(x)) # 将解码后的所有的int类型的值转成float类型
[23.0, 43.0, 5.0]
>>> json.loads('[23, 43, 5]', parse_int=lambda x: str(x)) # 将解码后的所有的int类型的值转成str类型
['23', '43', '5']
parse_constant=None
接受一个可调用对象,用于解码时对Infinity
、-Infinity
、NaN
或其他非法的Json数值的处理。
>>> def parse_cons(cons):
... if cons == 'Infinity':
... return 100000000
... elif cons == '-Infinity':
... return -100000000
... elif cons == 'NaN':
... return None
... else:
... raise Value(f"Can't convert this value {cons}")
...
>>> json.loads('[Infinity, -Infinity, NaN]', parse_constant=parse_cons)
[100000000, -100000000, None]
object_parse_hook=None
如果指定了该参数并且设置为一个可调用对象,那么Json对象将被解码成一个元素为二元组的列表,二元组的两个元素分别为Json对象中的键值对的键和值,并且列表中元素的顺序与Json对象中键值对的顺序一致。
>>> emp_info = {
'name': 'bob', 'age': 23, 'dept': 'sales', 'gender': 'male'}
>>> json.loads(json.dumps(emp_info), object_pairs_hook=str)
"[('name', 'bob'), ('age', 23), ('dept', 'sales'), ('gender', 'male')]"
>>> from collections import OrderedDict
>>> json.loads(json.dumps(emp_info), object_pairs_hook=OrderedDict)
OrderedDict([('name', 'bob'), ('age', 23), ('dept', 'sales'), ('gender', 'male')])
下面演示下该方法的简单用法:
>>> with open('res.json', encoding='utf-8') as f:
... json.load(f)
...
{
'status': 'success', 'code': 200, 'data': {
'username': 'bob', 'user_level': 6, 'nickname': 'playboy'}}