1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Python 标准库之 json 编码和解码器『详解』

Python 标准库之 json 编码和解码器『详解』

时间:2023-05-02 20:35:18

相关推荐

Python 标准库之 json 编码和解码器『详解』

Python 标准库之 json 编码和解码器

文章目录

Python 标准库之 json 编码和解码器一、Python json库介绍二、导入 json 库三、Python对应JSON数据类型四、基本使用「重点」🧊1、序列化操作2、反序列化操作五、编码器和解码器🥃六、异常🧃参考资料💖相关博客😋

一、Python json库介绍

JSON(JavaScript Object Notation)是由道格拉斯·克罗克福特构想和设计的一种轻量级资料交换格式。其内容由属性和值所组成,因此也有易于阅读和处理的优势。JSON是独立于编程语言的资料格式,其不仅是JavaScript的子集,也采用了C语言家族的习惯用法,目前也有许多编程语言都能够将其解析和字符串化,其广泛使用的程度也使其成为通用的资料格式。

Python 的json库提供了对json序列化的支持,与标准库marshalpickle相似的API接口。

二、导入 json 库

在看下列内容前,别忘记导入 json 标准库呀

import json

三、Python对应JSON数据类型

1)、JSON 到 Python 数据类型的转换

2)、Python 到 JSON 数据类型的转换

3)、源码查阅

在 JSON 标准库的编码器和解码器源码里,能看到对转换类型的注释

JSONEncoder

class JSONEncoder(object):"""Extensible JSON <> encoder for Python data structures.Supports the following objects and types by default:+-------------------+---------------+| Python | JSON|+===================+===============+| dict | object |+-------------------+---------------+| list, tuple | array |+-------------------+---------------+| str| string |+-------------------+---------------+| int, float | number |+-------------------+---------------+| True | true|+-------------------+---------------+| False | false |+-------------------+---------------+| None | null|+-------------------+---------------+To extend this to recognize other objects, subclass and implement a``.default()`` method with another method that returns a serializableobject for ``o`` if possible, otherwise it should call the superclassimplementation (to raise ``TypeError``)."""pass

JSONDecoder

class JSONDecoder(object):"""Simple JSON <> decoderPerforms the following translations in decoding by default:+---------------+-------------------+| JSON| Python |+===============+===================+| object | dict |+---------------+-------------------+| array | list |+---------------+-------------------+| string | str|+---------------+-------------------+| number (int) | int|+---------------+-------------------+| number (real) | float |+---------------+-------------------+| true| True |+---------------+-------------------+| false | False |+---------------+-------------------+| null| None |+---------------+-------------------+It also understands ``NaN``, ``Infinity``, and ``-Infinity`` astheir corresponding ``float`` values, which is outside the JSON spec."""pass

四、基本使用「重点」🧊

1、序列化操作

1)、json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

obj对象序列化为JSON格式化流形式并存储到 文件,需要注意的是 json 模块始终返回的是str字符串对象,因此在将 JSON 读写文件时应以文本模式操作,在序列化操作时应确保fp.write支持str写入。

参数如下:

obj:需要被序列化的对象fp:传入一个拥有.write()写入方法的文件对象,比如file-likeobject,需要注意的是应传入一个文本模式的文件对象,并且编码应当是 UTF-8 , UTF-16 或者 UTF-32 。skipkeys:在为True时(默认为False)跳过不是基本对象(包括str,intfloatboolNone)字典的键,否则引发一个TypeError异常。ensure_ascii:在为True时(默认为True),输出保证将所有输入的非ASCII字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。check_circular:检查循环。如果为False(默认为True),那么容器类型的循环引用检验会被跳过并且循环引用回引发一个OverflowError(或者更糟的情况)。allow_nan:数据类型之间的转换遵守。如果为False(默认为True),那么在对严格JSON规格范围外的float类型值(naninf-inf)进行序列化时会引发一个ValueError异常。如果为True,则使用它们的 JavaScript 等价形式(NaNInfinity-Infinity)。cls:JSON 编码器的类别,默认使用自带的JSONEncoder。如果想使用自定义的 JSON 编码器,比如说JSONEncoder子类,通过此参数实现。indent:控制缩进内容。

a、 默认值为None会选择最紧凑的表达,即一行数据。

b、 如果 indent 是一个非负整数或者字符串,那么 JSON 数组元素和对象成员会被美化输出为该值指定的缩进内容,使用一个正整数会让每一层缩进同样数量的空格。

如果indent是 4 那么将会以4个空格做完每一层的缩进,indent 是一个字符串 (比如 “\t”),那个字符串会被用于缩进每一层。

c、 如果缩进等级为零、负数或者"",则只会添加换行符,在每个缩进前都不会有字符。separators:分割字符,因为用两种分割字符,所以应该是一个(item_separator, key_separator)元组(项分割字符,键分割字符)。

但因为缩进参数indent的存在,separators的默认值会有两种变化,当indentNone时,会使用紧凑的一行表达,这时候的分割符会取值(', ', ': ')在每个分割符后都有空格,而相反在不为None时会取值(',', ':')

小技巧:为了得到最紧凑的 JSON 表达式,在 indent 为None的情况下,可以手动将 separators 取值为(',', ':'),也就是不留空格。default:被指定时,其应该是一个函数,每当某个对象无法被序列化时它会被调用,此函数接受一个参数,这个参数就是无法被序列化的对象。

它应该返回该对象的一个可以被 JSON 编码的版本或者引发一个TypeError。如果没有被指定,则会直接引发TypeError。sort_keys:如果为True(默认为 False),那么字典的输出会以键的顺序排序。

具体讲解:

取消非ASCII编码转义

在将 JSON 编码的数据存储到文件或是进行编码返回时,很容易发现除了ASCII字符都发生了转义,变成了Unicode的转义字符,最典型的例子就是中文字符。

# -*- coding: utf-8 -*-import jsonfrom pathlib import PathBASE_DIR = Path(__file__).parenthapply_new_year = {"年份": , "生肖": "虎", "祝福语": "在这美丽的春节之际,祝福各位朋友在新的一年里,天天都有份好心情!", "春节快乐": None}# 文件路径file_path = BASE_DIR / "test.json"# 打印输出到控制台print(json.dumps(happly_new_year))# 输出存储到文件with file_path.open("w", encoding="utf-8") as f_w:json.dump(happly_new_year, fp=f_w)

控制台输出 与 输出到文件

{"\u5e74\u4efd": , "\u751f\u8096": "\u864e", "\u795d\u798f\u8bed": "\u5728\u8fd9\u7f8e\u4e3d\u7684\u6625\u8282\u4e4b\u9645\uff0c\u795d\u798f\u5404\u4f4d\u670b\u53cb\u5728\u65b0\u7684\u4e00\u5e74\u91cc\uff0c\u5929\u5929\u90fd\u6709\u4efd\u597d\u5fc3\u60c5!", "\u6625\u8282\u5feb\u4e50": null}

那么对其进行 JSON 编码时如何取消发生的非 ASCII 字符转义,让这些字符会原样输出呢?答案很简单,在每次编码时将ensure_ascii参数设置为Flase即可。

上部分的代码保持不变,只是添加ensure_ascii参数

......# 打印输出到控制台print(json.dumps(happly_new_year, ensure_ascii=False))# 输出存储到文件with file_path.open("w", encoding="utf-8") as f_w:json.dump(happly_new_year, fp=f_w, ensure_ascii=False)

控制台输出 与 输出到文件

{"年份": , "生肖": "虎", "祝福语": "在这美丽的春节之际,祝福各位朋友在新的一年里,天天都有份好心情!", "春节快乐": null}

JSON 数据格式化

每次输出的 JSON 数据都是一行显示的,在数据量比较少的情况下还能阅读,当数据量一旦多起来后阅读体验上就没那么好了。JSON 本身就是一种注重数据结构化的格式,在维护调试时可以充分发挥其优点,对其进行格式化就是一种常见手段。

将其进行格式化返回需要使用到indent参数,indent参数的作用在参数讲解部分有将,这边咱们对这个参数作用进行展示。

以四个空格为缩进

# -*- coding: utf-8 -*-import jsonfrom pathlib import PathBASE_DIR = Path(__file__).parenthapply_new_year = {"年份": , "生肖": "虎","祝福语": "在这美丽的春节之际,祝福各位朋友在新的一年里,天天都有份好心情!","春节快乐": None}# 文件路径file_path = BASE_DIR / "test.json"# 打印输出到控制台print(json.dumps(happly_new_year, indent=4, ensure_ascii=False))# 输出存储到文件with file_path.open("w", encoding="utf-8") as f_w:json.dump(happly_new_year, fp=f_w, indent=4, ensure_ascii=False)

{"年份": ,"生肖": "虎","祝福语": "在这美丽的春节之际,祝福各位朋友在新的一年里,天天都有份好心情!","春节快乐": null}

以两个空格为缩进

......# 打印输出到控制台print(json.dumps(happly_new_year, indent=2, ensure_ascii=False))# 输出存储到文件with file_path.open("w", encoding="utf-8") as f_w:json.dump(happly_new_year, fp=f_w, indent=2, ensure_ascii=False)

{"年份": ,"生肖": "虎","祝福语": "在这美丽的春节之际,祝福各位朋友在新的一年里,天天都有份好心情!","春节快乐": null}

default 参数的妙用

default 其实是一个很方便的参数,向这个参数传入一个处理自定义对象的函数,就能够将这些自定义对象转义成可以被 JSON 编码的版本,而不需要在将数据序列化前还要手动转义 JSON 编码器无法解析的数据源。

有一个水果类,为每一种水果都新建一个对象,每个对象中都有一个方法可以将其转义成可以被 JSON 编码版本的方法,需要做的是在每次序列化时都能正确调用这个方法将其转义。这时 default 这个参数就派上用场了,传入 default 的函数要做两件事,如果是水果类的对象那就将其转义,如果不是则抛出异常。

# -*- coding: utf-8 -*-import jsonfrom pathlib import PathBASE_DIR = Path(__file__).parentclass Fruits:"""水果类"""def __init__(self, name, price):self.name = nameself.price = pricedef __str__(self):return f"水果类型:{self.name},售价:{self.price}"def todict(self):"""将水果信息转换成字典格式输出"""return {"水果": self.name, "售价": self.price}def obj_to_json(obj):"""对象转为JSON能编码函数Args:obj: 自定义对象Returns:能够被JSON编码的版本数据Raises:如果不是目标类别的对象将抛出TypeError异常"""if isinstance(obj, Fruits):return obj.todict()raise TypeError(f"Object of type {obj.__name__} is not JSON serializable")pear = Fruits("梨子", 3.3)apple = Fruits("苹果", 5.6)banana = Fruits("香蕉", 11.6)orange = Fruits("橙子", 6.6)fruits = [pear, apple, banana, orange]# 文件路径file_path = BASE_DIR / "test.json"with file_path.open("w", encoding="utf-8") as f_w:json.dump(fruits, fp=f_w, default=obj_to_json, ensure_ascii=False)

JSON 数据

[{"水果": "梨子", "售价": 3.3}, {"水果": "苹果", "售价": 5.6}, {"水果": "香蕉", "售价": 11.6}, {"水果": "橙子", "售价": 6.6}]

2)、json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

obj序列化为 JSON 格式的str对象并返回,不会进行文件式存储

除了缺少用于存储到文件的fp参数外,其它参数的含义与json.dump()中的相同,因此用法也是一样的,只不过一个是存储到文件,一个是直接返回 JSON 编码数据,这里不过多讲解

注解: JSON 中的键-值对中的键永远是 str 类型的。当一个对象被转化为 JSON 时,字典中所有的键都会被强制转换为字符串。这所造成的结果是字典被转换为 JSON 然后转换回字典时可能和原来的不相等。换句话说,如果 x 具有非字符串的键,则有 loads(dumps(x)) != x。比如说在Python数据类型中以整数为键,转化为 JSON 时这些整数将会变成字符串类型。

2、反序列化操作

1)、json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

fp(一个支持.read()并包含一个 JSON 文档的text file或者binary file) 反序列化为一个 Python 对象。

参数如下:

fp:传入一个拥有.read()写入方法的文件对象,该文件对象应是text file(文本对象)或binary file(二进制对象),对于二进制对象输入编码应当是 UTF-8 , UTF-16 或者 UTF-32。cls:JSON 解码器的类别,默认使用自带的 JSONDecoder。如果想使用自定义的 JSON 解码器,比如说 JSONDecoder 子类,通过此参数实现。额外的关键词参数会通过类的构造函数传递。object_hook:被指定时,其应该是一个函数。它会被调用于每一个解码出的对象字面量(一个dict、一个基本类型对象),此函数接受一个参数,这个参数就是每一个解码出的对象字面量。

该函数的返回值会取代原本的dict,简单来说就是该函数负责把反序列化后的基本类型对象转换成自定义类型的对象。这一特性能够被用于实现自定义解码器(如 JSON-RPC 的类型提示)。parse_float:解析浮点数。如果指定,将与每个要解码 JSON 浮点数的字符串一同调用。其应该是一个函数,同时接收一个参数,这个参数是每一个 JSON 浮点数的字符串。默认状态下,相当于float(num_str)

可以用于对 JSON 浮点数使用其它数据类型和语法分析程序 (比如decimal.Decimal)。parse_int:解析整数。如果指定,将与每个要解码 JSON 整数的字符串一同调用。其应该是一个函数,同时接收一个参数,这个参数是每一个 JSON 整数的字符串。默认状态下,相当于int(num_str)

可以用于对 JSON 整数使用其它数据类型和语法分析程序 (比如float)。parse_constant:解析常量。如果指定,将要与以下字符串中的一个一同调用:'-Infinity''Infinity''NaN'。其应该是一个函数,同时接收一个参数,这个参数是每一个 JSON 整数的字符串。如果遇到无效的 JSON 数字则可以使用它引发异常。object_pairs_hook:它会被调用于每一个有序列表对解码出的对象字面量,这个参数与object_hook参数功能相同,与object_hook参数不同点是给object_pairs_hook的解码的键值对列表是有序的,一些依赖键值对顺序的功能可以用object_pairs_hook参数,而不用object_hook

如果object_hook也被定义,object_pairs_hook优先。

具体讲解:

JSON 浮点数处理

parse_float参数用于控制 JSON 浮点数转化为 Python 数据类型时的操作,默认是对其转化为浮点数类型float(num_str),浮点数还能做的处理,比如四舍五入,向上向下取整,转化为decimal.Decimal等,这些都能直接靠parse_float参数实现。

# -*- coding: utf-8 -*-import mathimport jsonfrom pathlib import Pathfrom decimal import DecimalBASE_DIR = Path(__file__).parent# 文件路径file_path = BASE_DIR / "test.json"def json_ceil(dic):"""将json浮点数向上取整辅助函数"""return math.ceil(float(dic))def json_floor(dic):"""将json浮点数向下取整辅助函数"""return math.floor(float(dic))def json_round(dic):"""将json浮点数四舍五入取整辅助函数"""return round(float(dic))def float_to_decimal(dic):"""将json浮点数转化Decimal辅助函数"""return Decimal.from_float(float(dic)).......

源 JSON 数据

[{"水果": "梨子", "售价": 3.3}, {"水果": "苹果", "售价": 5.6}, {"水果": "香蕉", "售价": 11.6}, {"水果": "橙子", "售价": 6.6}]

向上取整

......with file_path.open("r", encoding="utf-8") as f_r:print(json.load(f_r, parse_float=json_ceil))

[{'水果': '梨子', '售价': 4}, {'水果': '苹果', '售价': 6}, {'水果': '香蕉', '售价': 12}, {'水果': '橙子', '售价': 7}]

向下取整

......with file_path.open("r", encoding="utf-8") as f_r:print(json.load(f_r, parse_float=json_floor))

[{'水果': '梨子', '售价': 3}, {'水果': '苹果', '售价': 5}, {'水果': '香蕉', '售价': 11}, {'水果': '橙子', '售价': 6}]

四舍五入取整

......with file_path.open("r", encoding="utf-8") as f_r:print(json.load(f_r, parse_float=json_round))

[{'水果': '梨子', '售价': 3}, {'水果': '苹果', '售价': 6}, {'水果': '香蕉', '售价': 12}, {'水果': '橙子', '售价': 7}]

转化为Decimal类型

......with file_path.open("r", encoding="utf-8") as f_r:print(json.load(f_r, parse_float=float_to_decimal))

[{'水果': '梨子', '售价': Decimal('3.29999999999999982236431605997495353221893310546875')}, {'水果': '苹果', '售价': Decimal('5.5999999999999996447286321199499070644378662109375')}, {'水果': '香蕉', '售价': Decimal('11.5999999999999996447286321199499070644378662109375')}, {'水果': '橙子', '售价': Decimal('6.5999999999999996447286321199499070644378662109375')}]

JSON 整数处理

在解析 JSON 整数字符串时,默认是将其转化为整数类型int(num_str),可以将其转化为浮点数类型,直接靠parse_float参数实现。

# -*- coding: utf-8 -*-import mathimport jsonfrom pathlib import Pathfrom decimal import DecimalBASE_DIR = Path(__file__).parentfile_path = BASE_DIR / "test.json"with file_path.open("r", encoding="utf-8") as f_r:print(json.load(f_r, parse_int=float))

源 JSON 数据

{"祝福语": "新春快乐!", "祝你": 1314}

程序打印

{'祝福语': '新春快乐!', '祝你': 1314.0}

object_hook 与 object_pairs_hook 的应用

object_hook参数与object_pairs_hook参数功能都是一致的,但在编写函数时,函数接受的参数不同。对于object_hook参数,传入的是每一个解码出来最基本的类型对象,即每次传入都是dict字典数据类型。对于object_pairs_hook参数,传入的是每一个解码出来的列表嵌套元组类型[(key, value), ],相当于调用了字典的.items()方法。

颁奖排序算是一个典型例子,以数字1、2、3…为颁奖奖次的依据,分别使用object_hook参数与object_pairs_hook参数进行示例。

# -*- coding: utf-8 -*-import jsons_data = '''{"3": ["第三名", "王汗"], "1": ["第一名", "王小明"], "2": ["第二名", "小明"],"4": ["第四名", "李华"], "5": ["第五名", "李大川"], "6": ["第六名", "xianzhe_"]}'''# 使用 object_hook 参数json.loads(s_data, object_hook=lambda x: print(f"类型:{type(x)},内容:{x}"))# 使用 object_pairs_hook 参数json.loads(s_data, object_pairs_hook=lambda x: print(f"类型:{type(x)},内容:{x}"))

"类型:<class 'dict'>,内容:{'3': ['第三名', '王汗'], '1': ['第一名', '王小明'], '2': ['第二名', '小明'], '4': ['第四名', '李华'], '5': ['第五名', '李大川'], '6': ['第六名', 'xianzhe_']}""类型:<class 'list'>,内容:[('3', ['第三名', '王汗']), ('1', ['第一名', '王小明']), ('2', ['第二名', '小明']), ('4', ['第四名', '李华']), ('5', ['第五名', '李大川']), ('6', ['第六名', 'xianzhe_'])]"

可以看到object_pairs_hook并没有返回一个有序列表,而是和object_hook一样的顺序,我的猜测是因为程序内部并不知道排序的依据是什么,但其实object_pairs_hook传入的参数是列表,那么自己手动指定排序即可

根据Key键值的排序返回

# -*- coding: utf-8 -*-import jsons_data = '''{"3": ["第三名", "王汗"], "1": ["第一名", "王小明"], "2": ["第二名", "小明"],"4": ["第四名", "李华"], "5": ["第五名", "李大川"], "6": ["第六名", "xianzhe_"]}'''def sort_hook(dic):"""将Json解码结果排序辅助函数如果是object_hook参数使用将直接返回Args:dic: 最基本的类型对象"""if isinstance(dic, list):dic.sort(key=lambda i: i[0])return dicelse:return dic# 使用 object_hook 参数print(json.loads(s_data, object_hook=sort_hook))# 使用 object_pairs_hook 参数print(json.loads(s_data, object_pairs_hook=sort_hook))

{'3': ['第三名', '王汗'], '1': ['第一名', '王小明'], '2': ['第二名', '小明'], '4': ['第四名', '李华'], '5': ['第五名', '李大川'], '6': ['第六名', 'xianzhe_']}[('1', ['第一名', '王小明']), ('2', ['第二名', '小明']), ('3', ['第三名', '王汗']), ('4', ['第四名', '李华']), ('5', ['第五名', '李大川']), ('6', ['第六名', 'xianzhe_'])]

两个参数同时存在的情况下,object_pairs_hook优先级更高

# -*- coding: utf-8 -*-import jsons_data = '''{"3": ["第三名", "王汗"], "1": ["第一名", "王小明"], "2": ["第二名", "小明"],"4": ["第四名", "李华"], "5": ["第五名", "李大川"], "6": ["第六名", "xianzhe_"]}'''def hook(dic):if isinstance(dic, list):return "object_pairs_hook优先"else:return "object_hook优先"print(json.loads(s_data, object_hook=hook, object_pairs_hook=hook))

object_pairs_hook优先

2)、json.loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

将JSON 编码的s字符串对象反序列化为一个 Python 对象。

json.loads()不同的是,不需要从一个文件对象走获取 JSON 编码数据,而是直接传入一个 JSON 编码的字符串对象,其它参数的含义与json.loads()中的相同,因此用法也是一样的,这里不过多讲解。

参数如下:

s:其实就是str的缩写,传入需要反 JSON 序列化的字符串对象

注解:如果反序列化的数据不是有效 JSON 文档,引发JSONDecodeError错误。

五、编码器和解码器🥃

1)、class json.JSONDecoder(*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None)

Python 实现 JSON 解码的重要组成部分,一个简单的 JSON 解码器。

在调用反序列化json.load()json.loads()方法时,传入的参数大部分实则传给了解码器,这也是参数名一致的原因。

同时将JSON 的NaNInfinity-Infinity理解为 Python 对应的float值。

源码:

通过查看源码可以看到,JSON 的反序列化方法实则是调用了JSONDecoder解码器。

部分源码

......if cls is None:cls = JSONDecoderif object_hook is not None:kw['object_hook'] = object_hookif object_pairs_hook is not None:kw['object_pairs_hook'] = object_pairs_hookif parse_float is not None:kw['parse_float'] = parse_floatif parse_int is not None:kw['parse_int'] = parse_intif parse_constant is not None:kw['parse_constant'] = parse_constantreturn cls(**kw).decode(s)

参数如下:

解码器的参数功能大部分与反序列化json.load()json.loads()方法一致。

object_hook:被指定时,其应该是一个函数。它会被调用于每一个解码出的对象字面量(一个dict、一个基本类型对象),此函数接受一个参数,这个参数就是每一个解码出的对象字面量。

该函数的返回值会取代原本的dict,简单来说就是该函数负责把反序列化后的基本类型对象转换成自定义类型的对象。这一特性能够被用于实现自定义解码器(如 JSON-RPC 的类型提示)。parse_float:解析浮点数。如果指定,将与每个要解码 JSON 浮点数的字符串一同调用。其应该是一个函数,同时接收一个参数,这个参数是每一个 JSON 浮点数的字符串。默认状态下,相当于float(num_str)。parse_int:解析整数。如果指定,将与每个要解码 JSON 整数的字符串一同调用。其应该是一个函数,同时接收一个参数,这个参数是每一个 JSON 整数的字符串。默认状态下,相当于int(num_str)。parse_constant:解析常量。如果指定,将要与以下字符串中的一个一同调用:'-Infinity''Infinity''NaN'。其应该是一个函数,同时接收一个参数,这个参数是每一个 JSON 整数的字符串。如果遇到无效的 JSON 数字则可以使用它引发异常。strict:严格模式。如果为False(默认为True),那么控制字符将被允许在字符串内。在此上下文中的控制字符编码在范围 0–31 内的字符,包括'\t'(制表符), '\n''\r''\0'。object_pairs_hook: 它会被调用于每一个有序列表对解码出的对象字面量,这个参数与object_hook参数功能相同,与object_hook参数不同点是给object_pairs_hook的解码的键值对列表是有序的,一些依赖键值对顺序的功能可以用object_pairs_hook参数,而不用object_hook

如果object_hook也被定义,object_pairs_hook优先。

方法功能

decode(s)

返回参数s的 Python 表示形式,参数s是包含一个 JSON 文档的字符串str实例。

raw_decode(s)

原始解码数据。从参数s中解码出 JSON 文档(以 JSON 文档开头的一个 str 对象)并返回一个 Python 表示形式为 2 元组以及指明该文档在 s 中结束位置的序号。

这可以用于从一个字符串解码JSON文档,该字符串的末尾可能有无关的数据。

2)、class json.JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)

Python 实现 JSON 解码的重要组成部分,用于Python数据结构的可扩展JSON编码器。

在调用序列化json.dump()json.dumps()方法时,传入的参数大部分实则传给了解码器,这也是参数名一致的原因。

为了将其拓展至识别其他对象,需要子类化并实现default()方法于另一种返回 o 的可序列化对象的方法如果可行,否则它应该调用超类实现(来引发TypeError)。

源码:

通过查看源码可以看到,JSON 的反序列化方法实则是调用了JSONDecoder解码器。

部分源码

......# cached encoderif (not skipkeys and ensure_ascii andcheck_circular and allow_nan andcls is None and indent is None and separators is None anddefault is None and not sort_keys and not kw):return _default_encoder.encode(obj)if cls is None:cls = JSONEncoderreturn cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,check_circular=check_circular, allow_nan=allow_nan, indent=indent,separators=separators, default=default, sort_keys=sort_keys,**kw).encode(obj)

参数如下:

skipkeys:在为True时(默认为False)跳过不是基本对象(包括str,intfloatboolNone)字典的键,否则引发一个TypeError异常。ensure_ascii:在为True时(默认为True),输出保证将所有输入的非ASCII字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。check_circular:检查循环。如果为False(默认为True),那么容器类型的循环引用检验会被跳过并且循环引用回引发一个OverflowError(或者更糟的情况)。allow_nan: 数据类型之间的转换遵守。如果为False(默认为True),那么在对严格JSON规格范围外的float类型值(naninf-inf)进行序列化时会引发一个ValueError异常。如果为True,则使用它们的 JavaScript 等价形式(NaNInfinity-Infinity)。sort_keys:在为True时(默认为False)跳过不是基本对象(包括str,intfloatboolNone)字典的键,否则引发一个TypeError异常。indent:控制缩进内容。

a、 默认值为None会选择最紧凑的表达,即一行数据。

b、 如果 indent 是一个非负整数或者字符串,那么 JSON 数组元素和对象成员会被美化输出为该值指定的缩进内容,使用一个正整数会让每一层缩进同样数量的空格。

如果indent是 4 那么将会以4个空格做完每一层的缩进,indent 是一个字符串 (比如 “\t”),那个字符串会被用于缩进每一层。

c、 如果缩进等级为零、负数或者"",则只会添加换行符,在每个缩进前都不会有字符。separators: 分割字符,因为用两种分割字符,所以应该是一个(item_separator, key_separator)元组(项分割字符,键分割字符)。

但因为缩进参数indent的存在,separators的默认值会有两种变化,当indentNone时,会使用紧凑的一行表达,这时候的分割符会取值(', ', ': ')在每个分割符后都有空格,而相反在不为None时会取值(',', ':')

小技巧:为了得到最紧凑的 JSON 表达式,在 indent 为None的情况下,可以手动将 separators 取值为(',', ':'),也就是不留空格。default:被指定时,其应该是一个函数,每当某个对象无法被序列化时它会被调用,此函数接受一个参数,这个参数就是无法被序列化的对象。

它应该返回该对象的一个可以被 JSON 编码的版本或者引发一个TypeError。如果没有被指定,则会直接引发TypeError

方法功能

default(o)

在子类中实现这种方法使其返回 o 的可序列化对象,或者调用基础实现(引发TypeError)。

比如说,为了支持任意迭代器,你可以像这样实现默认设置:

def default(self, o):try:iterable = iter(o)except TypeError:passelse:return list(iterable)# Let the base class default method raise the TypeErrorreturn json.JSONEncoder.default(self, o)encode(o)

返回 Python o 数据结构的 JSON 字符串表达方式。例如:

>>> json.JSONEncoder().encode({"foo": ["bar", "baz"]})'{"foo": ["bar", "baz"]}'

iterencode(o)

编码给定对象 o ,并且让每个可用的字符串表达方式。

for chunk in json.JSONEncoder().iterencode(bigobject):mysocket.write(chunk)

六、异常🧃

exception json.JSONDecodeError(msg, doc, pos)

参数如下:

msg

未格式化的错误消息doc

正在解析的 JSON 文档。pos

解析失败的 doc 的起始索引

源码:

源码比较简单,这里将源码贴出

class JSONDecodeError(ValueError):"""Subclass of ValueError with the following additional properties:msg: The unformatted error messagedoc: The JSON document being parsedpos: The start index of doc where parsing failedlineno: The line corresponding to poscolno: The column corresponding to pos"""# Note that this exception is used from _jsondef __init__(self, msg, doc, pos):lineno = doc.count('\n', 0, pos) + 1colno = pos - doc.rfind('\n', 0, pos)errmsg = '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos)ValueError.__init__(self, errmsg)self.msg = msgself.doc = docself.pos = posself.lineno = linenoself.colno = colnodef __reduce__(self):return self.__class__, (self.msg, self.doc, self.pos)

演示代码:

演示手动触发异常,一般也用不上,更多是用于理解源码是如何工作的

# -*- coding: utf-8 -*-import jsonerr_json = "{key: {\n'key2':value1}}}key3:value"raise json.JSONDecodeError("json数据格式错误", err_json, len(err_json))

json.decoder.JSONDecodeError: json数据格式错误: line 2 column 27 (char 34)

参考资料💖

维基百科中文版:Json控制字符Python 官方手册:json — JSON 编码和解码器

相关博客😋

Python 牛逼的 pip包管理工具Python 以优雅的姿势 操作文件

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。