Python3的Json模块详解

版权声明:版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/swinfans/article/details/86501555

简介

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.dumpjson.dumps这两个方法、的作用与使用方法类似,故只对其中之一详细介绍。

同样地,json.loadjson.loads这两个方法的作用与使用方法类似,故也只对其中之一详细介绍。

json.dumps

该方法包含一个位置参数和多个仅限关键字参数,分别如下所示:

  • 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 "<stdin>", 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 "<stdin>", 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 "<stdin>", 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-InfinityNaN)来进 行替代;

    如果该参数设置为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 "<stdin>", 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 "<stdin>", 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
    ]
    

json.dump

下面演示下该方法的简单用法:

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

json.loads

该方法包含一个位置参数和多个仅限关键字参数,分别如下所示:

  • 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-InfinityNaN或其他非法的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')])
    

    json.load

    下面演示下该方法的简单用法:

    >>> with open('res.json', encoding='utf-8') as f:
    ...     json.load(f)
    ... 
    {'status': 'success', 'code': 200, 'data': {'username': 'bob', 'user_level': 6, 'nickname': 'playboy'}}
    

猜你喜欢

转载自blog.csdn.net/swinfans/article/details/86501555