【问题标题】:How to pickle numpy ndarray derived class?如何腌制numpy ndarray派生类?
【发布时间】:2019-02-01 19:28:27
【问题描述】:

我腌制了一个派生自 ndarray 的类的实例,但在腌制/取消腌制期间丢失了属性。下面是用于说明问题的简化代码。我不明白:

  1. 为什么泡菜转储/加载中不包含“属性”?我需要做什么才能将其包含在内?
  2. 为什么在转储期间不调用 __getstate__() 以便我可以添加缺少的“atrrib”? __setstate__() 被调用。状态是如何设置的?我的想法是我会在 get 状态中添加“attrib”,以便稍后进行设置。
import numpy as np
import pickle

class Xndarray(np.ndarray):
    def __new__(cls, **kwargs):
        return super().__new__(cls, (5, 3), **kwargs)

    def __init__(self, **kwargs):
        self[...] = -1
        self.attrib = 0

    def add2getstate(self):
        print("add2getstate()", self.__dict__)   

    def __getstate__(self):                         # This never gets called
        print("__getstate__()")
        return super().__getstate__()

    def __setstate__(self, data):
        print("__setstate__()")
        super().__setstate__(data)


if __name__ == "__main__":
    fname = "fname.pkl"

    x = Xndarray()

    x[0] = 0
    x.attrib += 2

    print(x)
    x.add2getstate()
    print(x.attrib)

    with open(fname, "wb") as fh:
        pickle.dump(x, fh)

    print("---------------")

    with open(fname, "rb") as fh:
        y = pickle.load(fh)

    print(y)
    y.add2getstate()
    print(y.attrib)

这是输出:

[[ 0.  0.  0.]
 [-1. -1. -1.]
 [-1. -1. -1.]
 [-1. -1. -1.]
 [-1. -1. -1.]]
add2getstate() {'attrib': 2}
2
---------------
__setstate__()
[[ 0.  0.  0.]
 [-1. -1. -1.]
 [-1. -1. -1.]
 [-1. -1. -1.]
 [-1. -1. -1.]]
add2getstate() {}
Traceback (most recent call last):
  File "./t.py", line 48, in <module>
    print(y.attrib)
AttributeError: 'Xndarray' object has no attribute 'attrib'

【问题讨论】:

  • 我有与 numpy 数组相关的其他属性,我希望将这些属性与 numpy 数组一起保存。此外,numpy 数组是更大的序列化数据结构的一部分。

标签: python numpy multidimensional-array pickle


【解决方案1】:

__getstate__ 仅在您的对象使用默认 __reduce__/__reduce_ex__ 时才被调用。 numpy.ndarray 有自己的 __reduce__ 实现,它不会调用您的 __getstate__

numpy.ndarray.__reduce__ 只包括它知道的对象数据,而不包括self.attrib,并且numpy.ndarray.__setstate__ 不知道如何设置self.attrib,即使你以某种方式包含了该属性。

您需要实现自己的__reduce____setstate__ 并自己处理self.attrib

【讨论】:

  • 这就是我所需要的。谢谢。
【解决方案2】:

Numpy 数组不实现 __getstate__ 而是实现 __reduce__ 。

https://docs.python.org/2/library/pickle.html#pickling-and-unpickling-extension-types

【讨论】:

  • 谢谢(也感谢 user2357112)。我能够使用 __reduce__ 和更改 __setstate__ 让我的代码工作。当我搜索 __reduce__ 示例时,我发现我的问题已在 stackoverflow.com/questions/26598109/… 中得到解答。
【解决方案3】:

我不知道你为什么要实现__getstate__。 尝试删除__getstate__,然后它应该是完整的。

泡菜中没有self.attrib,因为您实现了自己的__getstate__,并仅从您继承的类中返回__getstate__

【讨论】:

  • 我实现了 getstate 来证明它在 pickle 转储期间没有被调用。删除它对输出没有影响。
  • 请在某处尝试并显示输出print(super().__getstate__())
  • Traceback (most recent call last): File "./np_pkl_tst.py", line 41, in &lt;module&gt; print(x.pr()) File "./np_pkl_tst.py", line 18, in pr print(super().__getstate__()) AttributeError: 'super' object has no attribute '__getstate__'
  • 是的,回报是确定的False。这来自 python 文档:“如果 __getstate__() 返回 false 值,则 __setstate__() 方法将不会在 unpickling 时被调用。”
【解决方案4】:

用莳萝代替泡菜https://pypi.org/project/dill/。由于 dill 从 pickle 扩展,界面几乎是相同的。

import dill
with open(fname, "wb") as fh:
    dill.dump(x,fh)

print("---------------")

with open(fname, "rb") as fh:
    y = dill.load(fh)

【讨论】:

  • 使用 dill 让我发布的测试用例工作。它不适用于我的完整项目,其中我有一个子类 numpy 对象的实例分配给第二个对象中的属性,其中第二个对象被腌制。为了让它发挥作用,我不得不使用 __reduce__ 和 __setstate__。
猜你喜欢
  • 2014-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 2018-10-10
  • 1970-01-01
  • 2016-02-10
  • 2013-02-04
相关资源
最近更新 更多