具有循环引用的pickle类的行为基于p不同

2024-06-16 09:50:11 发布

您现在位置:Python中文网/ 问答频道 /正文

如果类的__qualname__被设置为具有对自身的循环引用,则pickle的行为将根据协议而有所不同。以下脚本演示了该问题:

from __future__ import print_function

import pickle, sys

class Foo:
    __name__ = __qualname__ = "Foo.ref"
    pass

Foo.ref = Foo

print(sys.version_info)

for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
    print("{}:".format(proto), end=" ")
    try:
        pkl = pickle.dumps(Foo, proto)
        print("Dump OK,", end=" ")
        assert(pickle.loads(pkl) is Foo)
        print("Load OK,")
    except Exception as err:
        print(repr(err))

输出

Python2.7:
sys.version_info(major=2, minor=7, micro=16, releaselevel='final', serial=0)
0: Dump OK, Load OK,
1: Dump OK, Load OK,
2: Dump OK, Load OK,

Python3.7:
sys.version_info(major=3, minor=7, micro=3, releaselevel='final', serial=0)
0: RecursionError('maximum recursion depth exceeded while pickling an object')
1: RecursionError('maximum recursion depth exceeded while pickling an object')
2: RecursionError('maximum recursion depth exceeded while pickling an object')
3: RecursionError('maximum recursion depth exceeded while pickling an object')
4: Dump OK, Load OK,

这是commit使“可查找”对象(如未绑定方法)可pickle的副作用

请注意,我已经在Python bugs tracker中打开了一个issue。在StackOverflow上发布此消息,以接触更广泛的受众。我提出了以下三种解决方案

  1. 检查类是否具有自引用,并针对所有协议引发错误
  2. 使用备忘录处理自引用。我不确定在这种情况下应该丢弃什么。在上面的示例中Foo将存在于命名空间中,但不存在Foo.ref
  3. 转储类似于Python 2 pickle和Python 3 pickle协议的类>;=四,

Tags: anfoosysloadokdumppickleprint