如何在大量对象上找到Python Pickle中的错误源

时间:2011-07-05 23:09:19

标签: python serialization pickle

我已经接管了一个相当大的项目的代码。我正在尝试保存程序状态,并且有一个大型对象存储了几乎所有其他对象。我试图挑选这个对象,但是我得到了这个错误:

  

pickle.PicklingError:无法发现:它未被发现为内置 .module

从我在谷歌上可以找到的,这是因为某处我正在导入python init之外的东西,或者一个类属性引用了一个模块。所以,我有两个问题:

  1. 有人可以确认这就是为什么会出现这个错误的原因吗?我在代码中寻找正确的东西吗?

  2. 有没有办法找到哪一行代码/对象成员导致pickle的困难?回溯仅给出发生错误的pickle中的行,而不是被pickle对象的行。

4 个答案:

答案 0 :(得分:11)

2)你可以将pickle.Pickler和Monkey-patch子类化,以显示它的酸洗记录。这样可以更容易地追踪问题所在。

import pickle
class MyPickler (pickle.Pickler):
    def save(self, obj):
        print 'pickling object', obj, 'of type', type(obj)
        pickle.Pickler.save(self, obj)

这只适用于pickle.Pickler的Python实现。在Python 3.x中,pickle模块默认使用C实现,Pickler的纯Python版本称为_Pickler。

# Python 3.x
import pickle
class MyPickler (pickle._Pickler):
    def save(self, obj):
        print ('pickling object  {0} of type {1}'.format(obj, type(obj))
        pickle._Pickler.save(self, obj)

答案 1 :(得分:3)

#wrap { background: url(http://lorempixel.com/600/400); } .registerWrap { border-radius: 10px; border: 3px solid white; width: 45%; height: 500px; margin: 100px auto 40px auto; padding: 40px; text-align: center; background-color: #282828; opacity: 0.9; filter: alpha(opacity=90); /* For IE8 and earlier */ } .inputbar[type=text] { display: block; width: 400px; margin: 10px auto; font-size: 18px; padding: 10px; -webkit-transition: all 0.40s ease-in-out; -moz-transition: all 0.40s ease-in-out; -ms-transition: all 0.40s ease-in-out; -o-transition: all 0.40s ease-in-out; outline: none; border: 1px solid #DDDDDD; } .inputbar:hover { -moz-box-shadow: 0 0 10px #ccc; -webkit-box-shadow: 0 0 10px #ccc; box-shadow: 0 0 10px #ccc; } .inputbar[type=text]:focus { border: 1px solid #800000; -moz-box-shadow: 0 0 1px 1px rgba(128, 0, 0, 1); -webkit-box-shadow: 0 0 1px 1px rgba(128, 0, 0, 1); box-shadow: 0 0 1px 1px rgba(128, 0, 0, 1); } #registerButton[type=submit] { margin: 15px auto; width: 425px; font-size: 20px; font-weight: bold; padding: 14px; cursor: pointer; background-color: #800000; border: none; color: #FFFFFF; } #registerButton[type=submit]:hover { -moz-box-shadow: 0 0 10px #ccc; -webkit-box-shadow: 0 0 10px #ccc; box-shadow: 0 0 10px #ccc; }中存在类似的内容。让我们看一下对象列表,看看我们能做些什么:

<div id="wrap">
  <div class="registerWrap">
    <form action="" method="POST">
      <input type="text" class="inputbar" name="firstname" placeholder="First Name" required>
      <input type="text" class="inputbar" name="lastname" placeholder="Last Name" required>
      <input type="email" class="inputbaremail" name="email" placeholder="Email" required>
      <input type="tel" class="inputbarphone" name="phone_number" placeholder="Cell Phone Number" required>
      <input type="text" class="inputbar" name="username" placeholder="Username" autocomplete="off" required>
      <input type="password" name="password" placeholder="Password" class="inputbarp" required>
      <input type="password" name="password_again" placeholder="Confirm Password" class="inputbarp" required>
      <label for="registerButton">
        <input id="registerButton" type="submit" name="submit" value="Register">
      </label>
    </form>
  </div>

好的,dill无法挑选列表。那么问题是什么?

>>> import dill
>>> f = open('whatever', 'w')
>>> f.close()
>>> 
>>> l = [iter([1,2,3]), xrange(5), open('whatever', 'r'), lambda x:x]
>>> dill.detect.trace(False)
>>> dill.pickles(l)
False

好的,列表中的第一项无法腌制。剩下的呢?

dill

嗯。其他物品泡好了。所以,让我们替换第一个对象。

>>> dill.detect.trace(True)
>>> dill.pickles(l)
T4: <type 'listiterator'>
False

现在我们的对象泡菜。好吧,我们可以利用一些内置的对象共享,这些共享发生在linux / unix / mac上进行酸洗......那么更强大的检查呢,比如实际在子流程中进行酸洗(就像在Windows上发生的那样)?

>>> map(dill.pickles, l)
T4: <type 'listiterator'>
Si: xrange(5)
F2: <function _eval_repr at 0x106991cf8>
Fi: <open file 'whatever', mode 'r' at 0x10699c810>
F2: <function _create_filehandle at 0x106991848>
B2: <built-in function open>
F1: <function <lambda> at 0x1069f6848>
F2: <function _create_function at 0x1069916e0>
Co: <code object <lambda> at 0x105a0acb0, file "<stdin>", line 1>
F2: <function _unmarshal at 0x106991578>
D1: <dict object at 0x10591d168>
D2: <dict object at 0x1069b1050>
[False, True, True, True]

不,该列表仍然有用......所以这是一个可以成功发送到另一个进程的对象。

现在,关于你的错误,每个人似乎都忽略了......

>>> dill.detect.trace(False) >>> l[0] = xrange(1,4) >>> dill.pickles(l) True >>> _l = dill.loads(dill.dumps(l)) 对象不是pickleable,导致您的错误。

>>> dill.check(l)        
[xrange(1, 4), xrange(5), <open file 'whatever', mode 'r' at 0x107998810>, <function <lambda> at 0x1079ec410>]
>>> 

但是,如果我们导入ModuleType,它就会神奇地起作用。

>>> import types
>>> types.ModuleType 
<type 'module'>
>>>
>>> import pickle
>>> pickle.dumps(types.ModuleType)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps
    Pickler(file, protocol).dump(obj)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 748, in save_global
    (obj, module, name))
pickle.PicklingError: Can't pickle <type 'module'>: it's not found as __builtin__.module

答案 2 :(得分:2)

作为查找对象的哪个属性/成员导致问题的快速方法,您可以尝试:

for k, v in massiveobject.__dict__.iteritems():
    print k
    pickle.dumps(v)

答案 3 :(得分:1)

1)与您的发现略有不同。这是一个引用模块类型(不是模块直接)的变量(类属性,列表或dict项,它可能是任何东西)引起的问题。此代码应重现此问题:

import pickle
pickle.dumps(type(pickle))