【问题标题】:Pickling a subclass of an OrderedDict腌制 OrderedDict 的子类
【发布时间】:2017-08-24 11:07:53
【问题描述】:

以下陈述:

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

【问题讨论】:

  • 我想我可能已经找到了一个我认为可能对其他人有用的解决方案。添加:

标签: python python-3.x pickle ordereddictionary


【解决方案1】:

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

现在可以毫无问题地腌制:

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 并检查哪种方法最适合您。

【讨论】:

    猜你喜欢
    • 2014-01-16
    • 2012-04-14
    • 1970-01-01
    • 2018-10-27
    • 2011-06-06
    • 2019-08-15
    • 2021-03-30
    • 1970-01-01
    • 2020-10-16
    相关资源
    最近更新 更多