FakeModule
データをピクルスにしたときと、データをアンピックしようとしたときの間に変更したようです。具体的には、そのモジュールから、名前の付いたトップレベルオブジェクトWorld
(おそらくクラス、おそらく関数)を削除しました。
Picklingはクラスと関数を「名前で」シリアル化するため、モジュールのトップレベルの名前である必要があり、そのモジュールを変更しないでください(少なくとも、これらの名前に悪影響を与えるような方法ではなく、これらの名前をから削除することはできません)。モジュール!)ピクルス時間とアンピクルス時間の間。
選択解除を妨げる変更を正確に特定したら、他の理由で変更を元に戻すことができない場合、ハッキングされることがよくあります。たとえば、World
からFakeModule
に移動したばかりの場合は、次のようCoolModule
にします。
import FakeModule
import CoolModule
FakeModule.World = CoolModule.World
ピクルスを外す直前(そして、ピクルスを外すたびにこれらのハックを繰り返し続ける必要がないように、新しい構造でもう一度ピクルスにすることを忘れないでください;-)。
編集:OPによるQの編集により、彼のエラーがはるかに理解しやすくなります。__name__
彼は現在、等しいかどうかをテストしているので'__main__'
、これにより、ピクルスが書き込まれると、クラスのオブジェクトが保存されることが明らかになります__main__.World
。彼はASCIIピクルスを使用しているので(ちなみに、パフォーマンスとディスク容量の点で非常に悪い選択です)、以下を確認するのは簡単です。
$ cat file
(i__main__
World
p0
(dp1
検索されているモジュールは(明らかにそして明らかに)__main__
です。これで、ipythonを気にすることなく、単純なPythonインタラクティブインタープリターを使用できます。
$ py26
Python 2.6.5 (r265:79359, Mar 24 2010, 01:32:55)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import world
>>> import pickle
>>> pickle.load(open("file", "rb"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle.py", line 1370, in load
return Unpickler(file).load()
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle.py", line 858, in load
dispatch[key](self)
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle.py", line 1069, in load_inst
klass = self.find_class(module, name)
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'World'
>>>
エラーは簡単に再現でき、その理由も同様に明白です。クラス名のルックアップが実行されるモジュール(つまり、__main__
)には、実際には「World」という名前の属性がありません。モジュールworld
には1つありますが、回答の前の部分で説明したように、OPは「ドットを接続」しておらず、ピクルスファイルが必要とするモジュールに正しい名前の参照を配置しています。あれは:
>>> World = world.World
>>> pickle.load(open("file", "rb"))
<world.World instance at 0xf5300>
>>>
もちろん、これは完全に機能します(そして前に言ったように)。おそらく、OPは、私が嫌うインポートの形式を使用しているため、この問題を認識していませんfrom world import World
(モジュール自体ではなく、モジュール内から関数またはクラスを直接インポートします)。
ipythonの問題を回避するためのハックは、基盤となるPythonアーキテクチャに関してはまったく同じです。つまり、ipythonは、すべての追加サービスを提供するために、モジュールを直接利用可能にして、何を直接記録することができない__main__
ため、さらに数行のコードが必要です。インタラクティブなコマンドラインで発生しますが、1つを挿入し(OPがエラーメッセージから見つけたのでFakeModuleと呼ばれます;-)、「クール」になるためにそれを使って黒魔術を行います。それでも、特定の名前のモジュールに直接アクセスしたい場合は、もちろん、Pythonでは非常に簡単です。
In [1]: import world
In [2]: import pickle
In [3]: import sys
In [4]: sys.modules['__main__'].World = world.World
In [5]: pickle.load(open("file", "rb"))
Out[5]: <world.World instance at 0x118fc10>
In [6]:
保持する教訓、ナンバーワン:少なくとも、あなたが魔術師の見習いとして、時折の暴走状況を見つけて修正できるようになるまでは、黒魔術を避けてください(そうしないと、バケツを運ぶほうきが世界に殺到する可能性がありますあなたが昼寝している間;-)。
または、別の読み方:抽象化の特定のレイヤー(ipythonがPythonの上に置く「クールな」レイヤーなど)を適切に使用するには、基盤となるレイヤー(ここでは、Python自体とピクルスやsysなどのコアメカニズム)を十分に理解する必要があります.modules)。
__main__
レッスン2:そのpickleファイルは、モジュールに名前のクラスがある場合にのみロードできるため、作成方法が原因で本質的に壊れています。Word
もちろん、上記のようなハックがなければ通常はロードできません。代わりに、pickleファイルはクラスをモジュールに存在するものとして記録する必要がありますworld
。の句でファイルを作成する必要があると絶対に感じる場合は、次の目的で冗長性を使用してください。if __name__ == '__main__':
world.py
import pickle
class World:
""
if __name__ == '__main__':
import world
w = world.World()
pickle.dump(w, open("file", "wb"))
これは正常に機能し、ハッキングはありません(少なくとも、モジュールのトップレベルに実質的なコードがないというPythonのベストプラクティスに従っている場合は、インポート、クラス、定義、および些細な割り当てのみです。他のすべては関数に属します。このベストプラクティスに従ってから、コードを編集してください。柔軟性とパフォーマンスの両方の点で、はるかに幸せになります)。