python - pickle OrderedDict 的子类

标签 python python-3.x pickle ordereddictionary

以下语句:

import pickle
from collections import OrderedDict as Odict

class A(Odict):
    def __init__(self, items):
        super().__init__(items)

items = Odict((('a',1), ('b', 2)))
a = A(items)

with open('test.pickle','wb') as fout:
    pickle.dump(a, fout)

with open('test.pickle','rb') as fin:
    pickle.load(fin)

导致这个错误:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: __init__() missing 1 required positional argument: 'items'

但是使用普通的 dict 而不是 OrderedDict 效果很好。我知道在这种情况下我不需要 __init__,但这个问题阻止了将多处理模块与更复杂的 OrderedDict 子类一起使用,其中其他参数存储为属性,我无法避免拥有它。 (我使用的是 python 3.4.6)。

最佳答案

OrderedDict 覆盖 __reduce__如果您覆盖 __init____new__ 方法和/或想要存储其他属性,则需要覆盖它。

在你的例子中,你为 __init__ 设置了参数(对于 dictOrderedDict 不是强制的)所以你需要重写__reduce__ :

import collections

class OD(collections.OrderedDict):
    def __init__(self, items):
        super().__init__(items)

    def __reduce__(self):
        state = super().__reduce__()
        # OrderedDict.__reduce__ returns a 5 tuple
        # the first and last can be kept
        # the fourth is None and needs to stay None
        # the second must be set to an empty sequence
        # the third can be used to store attributes
        newstate = (state[0],
                    ([], ),
                    None,
                    None,
                    state[4])
        return newstate

现在可以毫无问题地 pickle :

import pickle

a = OD((('a',1), ('b', 2)))

with open('test.pickle','wb') as fout:
    pickle.dump(a, fout)

with open('test.pickle','rb') as fin:
    pickle.load(fin)

但是,如果您想要未在您的 __init__ 中设置的属性,这将无法正常工作:

a = OD((('a',1), ('b', 2)))
a.a = 10

with open('test.pickle','wb') as fout:
    pickle.dump(a, fout)

with open('test.pickle','rb') as fin:
    b = pickle.load(fin)

b.a  # AttributeError: 'OD' object has no attribute 'a'

要完成这项工作,您还需要更改上面提到的 __reduce__ 函数以返回第三个参数。例如你可以简单地返回 __dict__:

class OD(collections.OrderedDict):
    def __init__(self, items):
        super().__init__(items)

    def __reduce__(self):
        state = super().__reduce__()
        newstate = (state[0],
                    ([], ),
                    self.__dict__,
                    None,
                    state[4])
        return newstate

有了这个,上面的例子就可以正常工作了。


很多设计取决于您希望子类的行为方式。在某些情况下,通过第二个参数(传递给 __init__ 的那个)传递项目会更好。至于如何设置属性:有时使用 self.__dict__ 就足够了,但在其他情况下使用 __setstate__ 会更安全/更好。 .你绝对应该阅读 documentation of the pickle module并检查哪种方法最适合您。

关于python - pickle OrderedDict 的子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45860040/

相关文章:

python - pickle 使用 importlib.util 导入的对象

python - 保留(pickle)自定义 sklearn 管道的推荐方法是什么?

python - 在mongoengine中查询列表;包含与在

python - 如何使用 python 将 utf-8 字符正确插入 MySQL 表

python - Django 模型对象过滤相对于日期范围来查找创建对象的初始日期?

python - NameError:名称 'age' 未定义

使用 Pickler 时出现 Python Pickle EOFerror(但不使用 pickle.dump())

类中的python生成器

python - 通过 python 自动化 .get 请求

python - 获取 FB token Python