web-dev-qa-db-ja.com

カスタムクラスのピクルス

ファイルmyClass.pyに単純なpythonクラス定義があるとします。

class Test:
    A = []

また、2つのテストスクリプトもあります。最初のスクリプトは、タイプTestのオブジェクトを作成し、配列Aにデータを入力して、結果をファイルにピクルします。それはすぐにファイルからそれをunpickleし、配列はまだ入力されています。 2番目のスクリプトはファイルからピックル解除するだけで、配列にデータが入力されていません(つまり、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
23
Joe

これは、インスタンス属性ではなくクラス属性としてTest.Aを設定しているためです。実際に起こっていることは、test1.pyでは、pickleファイルから読み戻されるオブジェクトはtest2.pyと同じですが、最初にx.Aを割り当てたメモリ内のクラスを使用することです。

データがファイルからアンピックルされると、クラス型の新しいインスタンスが作成され、必要なインスタンスデータがすべて適用されます。しかし、あなたの唯一のデータはクラス属性でした。それは常に、メモリ内のクラスthatsを参照します。これは、1つのファイルでは変更されましたが、別のファイルでは変更されていません。

この例の違いを比較します。

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

インスタンス属性aは適切にピクルされ、アンピクルされますが、クラス属性Aはメモリ内のクラスを参照するだけです。

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

with open('data', 'w') as f:
    pickle.dump(x,f)

with open('data') 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
[]
30
jdi

これは古い質問です。もし今それを見たなら、おそらく__getstate__および__setstate__をクラスに追加すると、定義したクラスをダンプしてロードする方法がpickleにわかります。

examples を参照してください。

クラスが単純な場合(たとえば、メンバーとメソッドとしてintとstringのみを使用する場合)、自動的に選択可能になるはずです。

0
borgr