Python-序列化与反序列化

目录

简介

json

方法

对象序列化

反序列化

pickle

可以被打包/解包的对象

常量

方法

序列化

反序列化

安全

参考


简介

序列化

json

方法

对象序列化

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 格式化流形式的 fp
转换表

Python

JSON

dict

object

list, tuple

array

str

string

int, float, int 和 float 派生的枚举

number

True

true

False

false

None

null

  • 如果 skipkeys 是True,那么那些不是基本对象的字典的键会被跳过;否则引发一个TypeError。
  • 如果 ensure_ascii 是 True (即默认值),输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。
  • 如果 check_circular 是为False,那么容器类型的循环引用检验会被跳过并且循环引用会引发一个 OverflowError(或者更糟的情况)。
  • 如果 allow_nan 是 False,那么在对严格 JSON 规格范围外的float类型值(naninf-inf)进行序列化时会引发一个ValueError。如果 allow_nan 是 true,则使用它们的 JavaScript 等价形式(NaNInfinity-Infinity)。
  • 如果 indent 是一个非负整数或者字符串,那么 JSON 数组元素和对象成员会被美化输出为该值指定的缩进等级。如果缩进等级为 0、负数或者 "",则只会添加换行符。None``(默认值)选择最紧凑的表达。使用一个正整数会让每一层缩进同样数量的空格。如果 *indent* 是一个字符串(比如 ``"\t"),那个字符串会被用于缩进每一层。现允许使用字符串作为 indent 而不再仅仅是整数。
  • 当被指定时,separators 应当是一个 (item_separator, key_separator) 元组。当 indentNone 时,默认值取 (', ', ': '),否则取 (',', ': ')。为了得到最紧凑的 JSON 表达式,你应该指定其为 (',', ':') 以消除空白字符。现当 indent 不是 None 时,采用 (',', ': ') 作为默认值。
  • default 被指定时,其应该是一个函数,每当某个对象无法被序列化时它会被调用。它应该返回该对象的一个可以被 JSON 编码的版本或者引发一个TypeError。如果没有被指定,则会直接引发 TypeError。
  • 如果 sort_keys 是 true(默认为 False),那么字典的输出会以键的顺序排序。
  • 为了使用一个自定义的JSONEncoder子类(比如:覆盖了 default() 方法来序列化额外的类型), 通过 cls 关键字参数来指定;否则将使用JSONEncoder。
  • 所有可选形参现在都是仅限关键字参数。

常用的是这个函数:

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。 其参数的含义与dump中的相同。

>>> adict = {'s':'ss'}
>>> alist = [1,2]
>>> astr = 'lady_killer9'
>>> aint = 9
>>> aflag = True
>>> nothing = None
>>> json.dumps(adict)
'{"s": "ss"}'
>>> json.dumps(alist)
'[1, 2]'
>>> json.dumps(astr)
'"lady_killer9"'
>>> json.dumps(aint)
'9'
>>> json.dumps(aflag)
'true'
>>> json.dumps(nothing)
'null'

反序列化

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 文档的文本或二进制文件) 反序列化为一个 Python 对象。

转换表

JSON

Python

object

dict

array

list

string

str

number (int)

int

number (real)

float

true

True

false

False

null

None

  • object_hook 是一个可选的函数,它会被调用于每一个解码出的对象字面量(即一个dict)。object_hook 的返回值会取代原本的 dict。这一特性能够被用于实现自定义解码器。
  • object_pairs_hook 是一个可选的函数,它会被调用于每一个有序列表对解码出的对象字面量。 object_pairs_hook 的返回值将会取代原本的dict。这一特性能够被用于实现自定义解码器。如果 object_hook 也被定义, object_pairs_hook 优先。
  • parse_float ,如果指定,将与每个要解码 JSON 浮点数一同调用。默认状态下,相当于 float(num_str) 。可以用于对 JSON 浮点数使用其它数据类型和解析器 (比如decimal.Decimal)。
  • parse_int ,如果指定,将与每个要解码 JSON 整数的字符串一同调用。默认状态下,相当于 int(num_str) 。可以用于对 JSON 整数使用其它数据类型和语法分析程序 (比如float)。
  • parse_constant ,如果指定,将要与以下字符串中的一个一同调用: '-Infinity''Infinity''NaN' 。如果遇到无效的 JSON 数字它会被用于抛出异常。 parse_constant 不再调用 'null' , 'true' , 'false' 。
  • 要使用自定义的 JSONDecoder子类,用 cls 指定;否则使用JSONDecoder。额外的关键词参数会通过类的构造函数传递。如果反序列化的数据不是有效 JSON 文档,抛出JSONDecoderError错误。
  • 所有可选形参现在都是仅限关键字参数。
  •  fp 现在可以是二进制文件。输入编码应当是 UTF-8 , UTF-16 或者 UTF-32 。

对应dumps,常用的是这个函数:

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

使用上面的转换表将 s (一个包含 JSON 文档的str, bytes或bytearray实例) 反序列化为 Python 对象。

  • 其他参数与在load()中的含义相同,只有 encoding 被忽略和弃用。
  • 如果反序列化的数据不是有效 JSON 文档,抛出JSONDecoderError错误。
  •  s 现在可以为bytesbytearray类型。 输入编码应为 UTF-8, UTF-16 或 UTF-32。

>>> d = json.dumps(adict)
>>> json.loads(d)
{'s': 'ss'}
>>> type(json.loads(d))

>>> INT = json.dumps(aint)
>>> bb = bytes(INT,encoding='utf-8')
>>> json.loads(bb)
9

pickle

pickle应该是序列化 Python 对象时的首选,marshal存在主要是为了支持 Python 的 .pyc 文件.

可以被打包/解包的对象

下列类型可以被打包:

  • NoneTrueFalse

  • 整数、浮点数、复数

  • str、byte、bytearray

  • 只包含可打包对象的集合,包括 tuple、list、set 和 dict

  • 定义在模块顶层的函数(使用def定义,lambda函数不可以,因为lambda函数都是同样的名字)

  • 定义在模块顶层的内置函数

  • 定义在模块顶层的类

  • 某些类实例,这些类的__dict__属性值或__getstate()函数的返回值可以被打包。

常量

pickle.HIGHEST_PROTOCOL

整数,可用的最高协议版本。此值可以作为 protocol 值传递给dump()和dumps()函数,以及Pickler的构造函数。

pickle.DEFAULT_PROTOCOL

一个整数,表示封存操作使用的协议版本。 它可能小于HIGHEST_PROTOCOL。当前默认协议版本为 3,它是一个为 Python 3 设计的新协议。

方法

序列化

pickle.dump(obj, file, protocol=None, *, fix_imports=True)

将打包好的对象 obj 写入已打开的文件对象。它等同于 Pickler(file, protocol).dump(obj)

  • 可选参数 protocol 是一个整数,告知 pickler 使用指定的协议,可选择的协议范围从 0 到 HIGHEST_PROTOCOL。如果没有指定,这一参数默认值为 DEFAULT_PROTOCOL。指定一个负数就相当于指定 HIGHEST_PROTOCOL
  • 参数 file 必须有一个 write() 方法,该 write() 方法要能接收字节作为其唯一参数。因此,它可以是一个打开的磁盘文件(用于写入二进制内容),也可以是一个io.BytesIO实例,也可以是满足这一接口的其他任何自定义对象。
  • 如果 fix_imports 为 True 且 protocol 小于 3,pickle 将尝试将 Python 3 中的新名称映射到 Python 2 中的旧模块名称,因此 Python 2 也可以读取打包出的数据流。

常用的是这个函数:

pickle.dumps(obj, protocol=None, *, fix_imports=True)

obj 打包以后的对象作为bytes类型直接返回,而不是将其写入到文件。

  • 参数 protocolfix_imports 的含义与它们在dump()中的含义相同。

>>> import pickle
>>> pickle.dumps(adict)
b'\x80\x03}q\x00X\x01\x00\x00\x00sq\x01X\x02\x00\x00\x00ssq\x02s.'
>>> pickle.dumps(alist)
b'\x80\x03]q\x00(K\x01K\x02e.'
>>> pickle.dumps(astr)
b'\x80\x03X\x0c\x00\x00\x00lady_killer9q\x00.'
>>> pickle.dumps(aint)
b'\x80\x03K\t.'
>>> pickle.dumps(aflag)
b'\x80\x03\x88.'
>>> pickle.dumps(nothing)
b'\x80\x03N.'

反序列化

pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")

从已打开的文件对象中读取打包后的对象,重建其中特定对象的层次结构并返回。它相当于 Unpickler(file).load()

  • 参数 file 必须有两个方法,其中 read() 方法接受一个整数参数,而 readline() 方法不需要参数。两个方法都应返回字节串。 因此 file 可以是一个打开用于二进制读取的磁盘文件、一个io.BytesIO对象,或者任何满足此接口要求的其他自定义对象。
  • 可选的关键字参数是 fix_imports, encodingerrors,用于控制由Python 2 生成的 pickle 流的兼容性。如果 fix_imports 为 true,则 pickle 将尝试将旧的 Python 2 名称映射到 Python 3 中对应的新名称。encodingerrors 参数告诉 pickle 如何解码 Python 2 存储的 8 位字符串实例;这两个参数默认分别为 'ASCII' 和 'strict'。 encoding 参数可置为 'bytes' 来将这些 8 位字符串实例读取为字节对象。读取 NumPy array 和 Python 2 存储的 datetime、date和 time实例时,请使用 encoding='latin1'

常用的是这个函数:

pickle.loads(data, *, fix_imports=True, encoding="ASCII", errors="strict")

重建并返回一个对象的封存表示形式 data 的对象层级结构。 data 必须为类似字节类型的对象。

>>> b = pickle.dumps(alist)
>>> pickle.loads(b)
[1, 2]

安全

警告

未完待续...,等我找个序列化漏洞例子再来更新。

-------------2021年03月13日更新---------

今天进行了实践,写了个简单例子:网络安全-反序列化漏洞简介、攻击与防御

参考

Python3.7-pickle

你可能感兴趣的:(python,python,pickle,序列化)