pickleは、ファイルなどに保存するために、Python オブジェクトをバイト列にシリアライズするための標準ライブラリです。
どのようなオブジェクトがpickleできるかはpickleのレファレンスに記述がありますが、相互に参照しているオブジェクトがうまくunpickle出来ない現象が起きたので調べたところ、こちらのイシュートラッカーにあるとおり未解決の問題があるようです。
次のスクリプトを実行すると、pickle.loads
でunpickleする際に、AttributeError: 'Node' object has no attribute 'i'
となります。
# modified from https://bugs.python.org/file2428/circle.py
import pickle
class Node(object):
def __init__(self, i):
self.i = i
def __cmp__(self, other):
return cmp(self.i, other.i)
def __hash__(self):
return hash(self.i)
n = Node(12)
n.next_nodes = set((n,))
byteobj = pickle.dumps(n)
unpickled = pickle.loads(byteobj)
このエラーが起こるのは、Nodeオブジェクトのn
が次の条件にあてはまるからで、このような条件にあてはまるオブジェクトはpickle/unpickle出来ない可能性があります。
-
__hash__
メソッドで、自らのメンバーi
を使用している。 -
n
は、n.next_nodes
のset
オブジェクトの要素として、自らを循環参照している。 - 循環参照の過程で、(
set
の要素であるから)__hash__
メソッドが使用されている
2007年に報告されたバグですが、イシュートラッカーでは、レアなケースだし、修正するのは大変なので修正しないと開き直っており、未だ解決されていないようです。