私はnamedtuple
をピクルスしようとしています:
from collections import namedtuple
import cPickle
class Foo:
Bar = namedtuple('Bar', ['x', 'y'])
def baz(self):
s = set()
s.add(Foo.Bar(x=2, y=3))
print cPickle.dumps(s)
if __== '__main__':
f = Foo()
f.baz()
これにより、次の出力が生成されます。
Traceback (most recent call last):
File "scratch.py", line 15, in <module>
f.baz()
File "scratch.py", line 11, in baz
print cPickle.dumps(s)
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed
私は何を間違えていますか? Bar
はFoo
のメンバーですか? (Bar
の定義をトップレベルに移動すると問題が解決しますが、なぜこれが起こるのか私はまだ知りません。)
はい、クラスメンバーであるという事実は問題です。
>>> class Foo():
... Bar = namedtuple('Bar', ['x','y'])
... def baz(self):
... b = Foo.Bar(x=2, y=3)
... print(type(b))
...
>>> a = Foo()
>>> a.baz()
<class '__main__.Bar'>
問題は、namedtuple()
が型オブジェクトを返すとき、それがクラスメンバに割り当てられているという事実を認識しないことです。したがって、型オブジェクトにその型名が__main__.Bar
であることを伝えます。本当に__main__.Foo.Bar
である必要があります。
クラスをネストすると、アプリケーション内のオブジェクトのパスに依存して後で再構築するため、pickleは失敗します。
直接の解決策は、クラスをネストしないことです。つまり、Bar
定義をFoo
の外部に移動します。コードはすべて同じように機能します。
ただし、データを保存するために使用しないpickle
を使用することをお勧めします。 json
などの他のシリアル化形式、またはsqlite3
などのデータベースを使用します。
あなたはコードを変更したり、物事を動かしたり、時には小さな構造的な変更を加えたりすると、データがロードできなくなります。
それに加えて、pickleには他の欠点があります:遅い、安全でない、Pythonのみです...
ここで漬物の代わりにディルを使用すると、これが機能します