【问题标题】:Pickle with custom classes带有自定义类的泡菜
【发布时间】:2012-06-06 05:43:48
【问题描述】:

假设我在 myClass.py 文件中有一个简单的 python 类定义

class Test:
    A = []

我还有两个测试脚本。第一个脚本创建一个 Test 类型的对象,填充数组 A,并将结果腌制到一个文件中。它立即将其从文件中解开,并且仍然填充数组。 第二个脚本只是从文件中提取出来,数组没有被填充(即 A == [])。这是为什么呢?

test1.py

import myClass
import pickle

x = myClass.Test()

for i in xrange(5):
    x.A.append(i)

f = open('data', 'w')
pickle.dump(x,f)
f.close()

f = open('data')
y = pickle.load(f)
f.close

print y.A

和 test2.py

import myClass
import pickle

f = open('data')
y = pickle.load(f)
f.close

print y.A

【问题讨论】:

    标签: python pickle


    【解决方案1】:

    这是因为您将Test.A 设置为类属性而不是实例属性。真正发生的事情是,对于 test1.py,从 pickle 文件中读回的对象与 test2.py 相同,但它使用了您最初分配 x.A 的内存中的类。

    当您从文件中提取数据时,它会创建一个类类型的新实例,然后应用它需要的任何实例数据。但是您唯一的数据是类属性。它总是引用内存中的类,你在一个文件中修改了它,而不是在另一个文件中。

    比较本例中的差异:

    class Test:
        A = []  # a class attribute
        def __init__(self):
            self.a = []  # an instance attribute
    

    您会注意到实例属性a 将被正确地腌制和取消腌制,而类属性A 将仅引用内存中的类。

    for i in range(5):
        x.A.append(i)
        x.a.append(i)  
    
    with open('data', 'wb') as f:
        pickle.dump(x,f)
    
    with open('data', 'rb') as f:
        y = pickle.load(f)
    
    >>> y.A
    [0, 1, 2, 3, 4]
    >>> y.a
    [0, 1, 2, 3, 4]
    >>> Test.A
    [0, 1, 2, 3, 4]
    >>> Test.A = []  # resetting the class attribute
    >>> y.a 
    [0, 1, 2, 3, 4]
    >>> y.A  # refers to the class attribute
    []
    

    【讨论】:

    • 这是否意味着如果你已经对类本身进行了腌制pickle.dump(Test),然后取消腌制了该类,那么在这两种情况下你都会得到正确的列表A
    • @BallpointBen,不,它不会保留类属性,根据what-can-be-pickled-and-unpickled:“类是通过命名引用腌制的,因此在 unpickling 环境中适用相同的限制。请注意,没有类的代码或数据被腌制”
    • 如果类变量和实例变量同名,pickle会选择类还是实例变量?
    • 如果你要设置一个实例变量A,那么它将隐藏类变量A。在那一点上,无论如何您都有一个与类变量分离的值。所以答案是你在pickle/unpickle时得到实例变量值
    • 不应该是open('data','wb')stackoverflow.com/a/13906715/2097158
    【解决方案2】:

    这是一个老问题,如果你现在看到它,你可能想要设置你的类的__getstate____setstate__,这样pickle 就会知道如何转储和加载你定义的类。

    在此处查看examples

    如果你的类很简单(例如,只有整数和字符串作为成员和任何方法),它应该可以自动选择。

    【讨论】:

      猜你喜欢
      • 2019-02-23
      • 1970-01-01
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-20
      • 2011-01-27
      相关资源
      最近更新 更多