如何使用iPython进行unpickling? [英] How to get unpickling to work with iPython?

查看:86
本文介绍了如何使用iPython进行unpickling?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在iPython中加载pickled对象。



我得到的错误是:



< blockquote>

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


任何人都知道如何获取它工作,或至少在iPython中加载对象的解决方法,以交互方式浏览它们?



谢谢



编辑添加:



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

  import pickle 
class World:

if __name__ =='__ main__':
w = World()
pickle.dump(w ,打开(文件,wb))

比在REPL我做:

 从世界进口中导入泡菜
World
w = pickle.load(open(file,rb) ))

在vanilla python REPL中有效但在iPython中无效。



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

解决方案

看起来你已修改 FakeModule 在您腌制数据的时间和尝试取消数据的时间之间:具体来说,您已从该模块中删除了一些名为 World (也许是一个类,也许是一个函数)。



Pickling序列化类和函数按名称,所以它们需要是名字在他们的模块的顶级该模块不能被修改(至少不会以这种方式严重影响这些名称 - 绝对 删除模块中的那些名字!)在酸洗时间和去除时间之间。



一旦你确定了你做了什么改变阻碍了破坏,它通常可以如果由于其他原因你不能只是恢复变化,被黑客攻击。例如,如果您刚刚将 World FakeModule 移至 CoolModule ,do:

  import FakeModule 
import CoolModule
FakeModule.World = CoolModule.World

就在解开之前(记得再次使用新结构腌制,这样你就不必再重复了这些黑客每次你破坏; - )。



编辑:OP编辑的Q使他的错误更容易理解。由于他现在正在测试 __ name __ 等于'__ main __',这很明显,当写入时,pickle将是保存类的对象 __ main __。World 。由于他使用ASCII泡菜(顺便说一句非常糟糕的性能和磁盘空间选择),所以检查是非常简单的:

  $ cat file 
(i__main__
World
p0
(dp1

正在查找的模块(显而易见) __ main __ 。现在,甚至没有打扰ipython,而是使用简单的Python交互式解释器:

  $ py26 
Python 2.6.5(r265:79359,2010年3月24日,01:32:55)
[GCC 4.0.1(Apple Inc. build 5493)]在darwin上
输入help,copyright,credits或license以获取更多信息。
>> ;>导入世界
>>>导入pickle
>>> pickle.load(打开(file,rb))
Traceback(最近一次)最后调用):
文件< stdin>,第1行,在< module>
文件/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle .py,第1370行,加载
返回Unpickler(文件).load()
Fi le/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle.py,第858行,加载
dispatch [key](self)
文件/ Library /Frameworks/Python.framework/Versions/2.6/lib/python2.6/pickle.py,第1069行,在load_inst
klass = self.find_class(模块,名称)
文件/ Library / Frameworks / Python.framework / Versions / 2.6 / lib / python2.6 / pickle.py,第1126行,在find_class
klass = getattr(mod,name)
AttributeError:'module'对象没有属性'World'
>>>

错误可以轻松复制,其原因同样明显:该类的模块执行name的查找(即 __ main __ )确实没有名为World的属性。模块 world 确实有一个,但是OP没有连接点,正如我在答案的前一部分中所解释的那样,在模块中添加了正确名称的引用其中pickle文件需要它。即:

 >>> World = world.World 
>>> pickle.load(open(file,rb))
< world.World instance at 0xf5300>
>>>

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



在ipython中解决问题的方法与底层Python架构完全相同 - 只需要几行代码,因为ipython ,为了提供所有额外的服务,使模块 __ main __ 直接可用于直接记录在交互式命令行中发生的事情,而是设置一个(称为FakeModule,正如OP从错误消息中发现的那样;-)并用它做黑魔法以便酷& c。尽管如此,每当你想直接使用给定名称的模块时,它在Python中都是微不足道的,当然:

  In [1]:import world 

在[2]中:import pickle

在[3]中:import sys

在[4]中:sys .modules ['__ main __']。World = world.World

在[5]中:pickle.load(open(file,rb))
Out [5]: < world.World instance at 0x118fc10>

在[6]中:

要保留的课程,第一:避免黑魔法,至少除非并且直到你足够好作为巫师的学徒能够发现并修复偶尔失控的情况(否则,那些携带桶的扫帚可能会在你打盹的时候淹没世界; - )。 / p>

或者,替代阅读:要正确使用某个抽象层(例如ipython放在Python之上的酷)你需要深入了解底层(这里,Python本身及其核心机制,如pickling和sys.modules)。



第二课:由于你的方式,那个pickle文件基本上已经坏了写了它,因为它只能在模块 __ main __ 有一个名为 Word 的类时加载,当然它通常不会没有像上面那样的一些黑客。 pickle文件应该将类记录为生活在模块 world 中。如果您绝对认为必须上生成文件,如果 world.py中的__name__ =='__ main __':子句,然后为此目的使用一些冗余:

  import pickle 
class World:

if __name__ =='__ main__':
import world
w = world.World()
pickle.dump(w,open(file, wb))

这很好,没有黑客攻击(至少如果你遵循Python的最佳实践从来没有任何实质性的代码在模块顶层 - 只有import,class,def和普通的赋值 - 其他一切都属于函数;如果你没有遵循这个最佳实践,那么编辑你的代码这样做,它会使在灵活性和性能方面,你很多更快乐。)


I'm trying to load pickled objects in iPython.

The error I'm getting is:

AttributeError: 'FakeModule' object has no attribute 'World'

Anybody know how to get it to work, or at least a workaround for loading objects in iPython in order to interactively browse them?

Thanks

edited to add:

I have a script called world.py that basically does:

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

Than in a REPL I do:

import pickle  
from world import World  
w = pickle.load(open("file", "rb"))

which works in the vanilla python REPL but not with iPython.

I'm using Python 2.6.5 and iPython 0.10 both from the Enthought Python Distribution but I was also having the problem with previous versions.

解决方案

Looks like you've modified FakeModule between the time you pickled your data, and the time you're trying to unpickle it: specifically, you have removed from that module some top-level object named World (perhaps a class, perhaps a function).

Pickling serializes classes and function "by name", so they need to be names at their module's top level and that module must not be modified (at least not in such way to affect those names badly -- definitely not by removing those names from the module!) between pickling time and unpickling time.

Once you've identified exactly what change you've done that impedes the unpickling, it can often be hacked around if for other reasons you can't just revert the change. For example, if you've just moved World from FakeModule to CoolModule, do:

import FakeModule
import CoolModule
FakeModule.World = CoolModule.World

just before unpickling (and remember to pickle again with the new structure so you won't have to keep repeating these hacks every time you unpickle;-).

Edit: the OP's edit of the Q makes his error much easier to understand. Since he's now testing if __name__ equals '__main__', this makes it obvious that the pickle, when written, will be saving an object of class __main__.World. Since he's using ASCII pickles (a very bad choice for performance and disk space, by the way), it's trivial to check:

$ cat file
(i__main__
World
p0
(dp1

the module being looked up is (clearly and obviously) __main__. Now, without even bothering ipython but with a simple Python interactive interpreter:

$ 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'
>>> 

the error can be easily reproduced, and its reason is just as obvious: the module in which the class name's lookup is performed (that is, __main__) does indeed have no attribute named "World". Module world does have one, but the OP has not "connected the dots" as I explained in the previous part of the answer, putting a reference with the right name in the module in which the pickled file needs it. That is:

>>> World = world.World
>>> pickle.load(open("file", "rb"))
<world.World instance at 0xf5300>
>>> 

now this works just perfectly, of course (and as I'd said earlier). Perhaps the OP is not seeing this problem because he's using the form of import I detest, from world import World (importing directly a function or class from within a module, rather than the module itself).

The hack to work around the problem in ipython is exactly the same in terms of underlying Python architecture -- just requires a couple more lines of code because ipython, to supply all of its extra services, does not make module __main__ directly available to record directly what happens at the interactive command line, but rather interposes one (called FakeModule, as the OP found out from the error msg;-) and does black magic with it in order to be "cool" &c. Still, whenever you want to get directly to a module with a given name, it's pretty trivial in Python, of course:

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]: 

Lesson to retain, number one: avoid black magic, at least unless and until you're good enough as a sorcerer's apprentice to be able to spot and fix its occasional runaway situations (otherwise, those bucket-carrying brooms may end up flooding the world while you nap;-).

Or, alternative reading: to properly use a certain layer of abstraction (such as the "cool" ones ipython puts on top of Python) you need strong understanding of the underlying layer (here, Python itself and its core mechanisms such as pickling and sys.modules).

Lesson number two: that pickle file is essentially broken, due to the way you've written it, because it can be loaded only when module __main__ has a class by name Word, which of course it normally will not have without some hacks like the above. The pickle file should instead record the class as living in module world. If you absolutely feel you must produce the file on an if __name__ == '__main__': clause in world.py, then use some redundancy for the purpose:

import pickle
class World:
    ""
if __name__ == '__main__':
    import world
    w = world.World()
    pickle.dump(w, open("file", "wb"))

this works fine and without hacks (at least if you follow the Python best practice of never having any substantial code at module top level -- only imports, class, def, and trivial assignments -- everything else belongs in functions; if you haven't followed this best practice, then edit your code to do so, it will make you much happier in terms of both flexibility and performance).

这篇关于如何使用iPython进行unpickling?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆