如何使用iPython进行unpickling?

Nil*_*urg 7 python pickle ipython

我正在尝试在iPython中加载pickle对象.

我得到的错误是:

AttributeError:'FakeModule'对象没有属性'World'

有人知道如何让它工作,或者至少是在iPython中加载对象以便以交互方式浏览它们的解决方法吗?

谢谢

编辑添加:

我有一个名为world.py的脚本基本上可以:

import pickle
class World:
    ""
if __name__ == '__main__':
    w = World()
    pickle.dump(w, open("file", "wb"))
Run Code Online (Sandbox Code Playgroud)

比在REPL我做:

import pickle  
from world import World  
w = pickle.load(open("file", "rb"))
Run Code Online (Sandbox Code Playgroud)

它适用于vanilla python REPL但不适用于iPython.

我正在使用来自Enthought Python Distribution的Python 2.6.5和iPython 0.10,但我也遇到了以前版本的问题.

Ale*_*lli 11

看起来你在FakeModule腌制数据的时间和你试图取消数据的时间之间进行了修改:具体来说,你已经从该模块中删除了一些名为的顶层对象World(可能是一个类,也许是一个函数).

酸洗序列化"的名字"类和功能,因此他们需要在自己的模块的顶级名称该模块不能被修改(至少不会以这样的方式来影响这些名字不好-绝对不是通过移除从那些名字模块!)在酸洗时间和开槽时间之间.

一旦你确定你做了什么改变阻碍了破坏,它通常会被黑客攻击,如果由于其他原因你不能只是恢复变化.举例来说,如果你刚搬到WorldFakeModuleCoolModule,这样做:

import FakeModule
import CoolModule
FakeModule.World = CoolModule.World
Run Code Online (Sandbox Code Playgroud)

在取消开始之前(并且记得再次使用新结构进行腌制,这样你就不必在每次开发时都不断重复这些黑客攻击;-).

编辑:OP对Q的编辑使他的错误更容易理解.由于他现在正在测试是否__name__等于'__main__',这很明显,当写入时,pickle将保存一个类的对象__main__.World.由于他使用的是ASCII泡菜(顺便说一句,这是性能和磁盘空间的一个非常糟糕的选择),因此检查它是微不足道的:

$ cat file
(i__main__
World
p0
(dp1
Run Code Online (Sandbox Code Playgroud)

正在查找的模块(清楚而明显地)__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'
>>> 
Run Code Online (Sandbox Code Playgroud)

错误可以很容易地重现,其原因同样明显:执行类名查找的模块(即__main__)确实没有名为"World"的属性.模块world确实有一个,但OP没有"连接点",正如我在答案的前一部分中所解释的那样,在pickle文件需要的模块中放入一个正确名称的引用.那是:

>>> World = world.World
>>> pickle.load(open("file", "rb"))
<world.World instance at 0xf5300>
>>> 
Run Code Online (Sandbox Code Playgroud)

现在,这当然完美无缺(正如我之前所说).也许OP没有看到这个问题,因为他正在使用导入的形式我讨厌,from world import World(直接从模块中导入函数或类,而不是模块本身).

解决在IPython中的问题的黑客正是在底层的Python架构方面是相同的-只是需要的代码,因为IPython中,以提供其所有的额外服务一对夫妇更行,并没有使模块__main__直接提供直接记录什么发生在交互式命令行,而是插入一个(称为FakeModule,作为从错误消息发现的OP ;-)并用它做黑魔术以便"酷"&c.但是,无论何时你想直接使用具有给定名称的模块,它在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]: 
Run Code Online (Sandbox Code Playgroud)

保留的教训,排名第一:避免使用黑魔法,至少除非并且直到你作为巫师的学徒能够发现和修复偶尔失控的情况(否则,那些携带桶的扫帚可能最终充斥世界)而你小睡;-).

或者,替代阅读:要正确使用某一抽象层(例如ipython放在Python之上的"酷"),您需要对底层(这里,Python本身及其核心机制,如酸洗和sys)有深刻理解.modules).

第二课:由于你编写它的方式,pickle文件基本上被破坏了,因为只有当模块__main__按名称有一个类时才可以加载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"))
Run Code Online (Sandbox Code Playgroud)

这很好,没有黑客攻击(至少如果你遵循Python最佳实践,在模块顶层没有任何实质性代码 - 只有导入,类,def和琐碎的任务 - 其他一切都属于函数;如果你没有'遵循这个最佳实践,然后编辑您的代码,这将使您在灵活性和性能方面更加快乐).