PicklingError:不能pickle <class'minit.decimal'=“”>:它与decimal.Decimal </class>不是同一个对象

时间:2009-09-11 19:13:24

标签: python django pickle

这是我今天在http://filmaster.com上收到的错误“&gt; filmaster.com:

  

PicklingError:不能发泡:它不一样   object as decimal.Decimal

这究竟是什么意思?它似乎没有多大意义...... 它似乎与django缓存有关。你可以在这里看到整个追溯:

  

追踪(最近一次呼叫最后一次):

     

文件   “/home/filmaster/django-trunk/django/core/handlers/base.py”   第92行,在get_response response =中   回调(request,* callback_args,   ** callback_kwargs)

     

文件   “/home/filmaster/film20/film20/core/film_views.py”   第193行,在show_film中   workflow.set_data_for_authenticated_user()

     

文件   “/home/filmaster/film20/film20/core/film_views.py”   518号线,在   set_data_for_authenticated_user
  object_id = self.the_film.parent.id)

     

文件   “/home/filmaster/film20/film20/core/film_helper.py”   第179行,在get_others_ratings中   set_cache(CACHE_OTHERS_RATINGS,   str(object_id)+“_”+ str(user_id),   userratings)

     

文件   “/home/filmaster/film20/film20/utils/cache_helper.py”   第80行,在set_cache中返回   cache.set(CACHE_MIDDLEWARE_KEY_PREFIX   + full_path,result,get_time(cache_string))

     

文件   “/home/filmaster/django-trunk/django/core/cache/backends/memcached.py”   第37行,在集合中   self._cache.set(smart_str(key),value,   超时或self.default_timeout)

     

文件   “/usr/lib/python2.5/site-packages/cmemcache.py”   第128行,在set val中,flags =   self._convert(VAL)

     

文件   “/usr/lib/python2.5/site-packages/cmemcache.py”   第112行,在_convert val =   pickle.dumps(val,2)

     

PicklingError:不能发泡:它不一样   object as decimal.Decimal

可以从此处下载Filmaster的源代码:bitbucket.org/filmaster/filmaster-test

非常感谢任何帮助。

10 个答案:

答案 0 :(得分:43)

在jupyter笔记本中运行时出现此错误。我认为问题在于我使用 public static void main(String[] args) throws IOException { List<Pojo> pojoList = new ArrayList<>(); BufferedReader reader = new BufferedReader(new FileReader("chat.txt")); String s; String[] data; while ((s = reader.readLine()) != null) { data = s.split(","); pojoList.add(new Pojo(Double.parseDouble(data[0]), data[1])); } Collections.sort(pojoList); FileWriter writer = new FileWriter("output.txt"); for (Pojo cur : pojoList) writer.write(cur.toString() + "\n"); reader.close(); writer.close(); } %load_ext autoreload。重新启动我的内核并重新运行解决了这个问题。

答案 1 :(得分:20)

Pickle的一个奇怪之处在于,在你挑选其中一个实例之前导入类的方式可以巧妙地改变pickle对象。 Pickle要求你在腌制它之前和取消它之前相同地导入对象。

例如:

from a.b import c
C = c()
pickler.dump(C)

会将一个微妙的不同对象(有时)制作成:

from a import b
C = b.c()
pickler.dump(C)

尝试摆弄你的导入,它可能会解决问题。

答案 2 :(得分:3)

您是否以某种方式reload(decimal)或monkeypatch十进制模块来更改Decimal类?这些是最有可能产生这种问题的两件事。

答案 3 :(得分:3)

通过调用multiprocessing__init__启动流程可能会出现问题。这是一个演示:

import multiprocessing as mp

class SubProcClass:
    def __init__(self, pipe, startloop=False):
        self.pipe = pipe
        if startloop:
            self.do_loop()

    def do_loop(self):
        while True:
            req = self.pipe.recv()
            self.pipe.send(req * req)

class ProcessInitTest:
    def __init__(self, spawn=False):
        if spawn:
            mp.set_start_method('spawn')
        (self.msg_pipe_child, self.msg_pipe_parent) = mp.Pipe(duplex=True)

    def start_process(self):
        subproc = SubProcClass(self.msg_pipe_child)
        self.trig_proc = mp.Process(target=subproc.do_loop, args=())
        self.trig_proc.daemon = True
        self.trig_proc.start()

    def start_process_fail(self):
        self.trig_proc = mp.Process(target=SubProcClass.__init__, args=(self.msg_pipe_child,))
        self.trig_proc.daemon = True
        self.trig_proc.start()

    def do_square(self, num):
        # Note: this is an synchronous usage of mp,
        # which doesn't make sense. But this is just for demo
        self.msg_pipe_parent.send(num)
        msg = self.msg_pipe_parent.recv()
        print('{}^2 = {}'.format(num, msg))

现在,使用上面的代码,如果我们运行它:

if __name__ == '__main__':
    t = ProcessInitTest(spawn=True)
    t.start_process_fail()
    for i in range(1000):
        t.do_square(i)

我们收到此错误:

Traceback (most recent call last):
  File "start_class_process1.py", line 40, in <module>
    t.start_process_fail()
  File "start_class_process1.py", line 29, in start_process_fail
    self.trig_proc.start()
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 105, in start
    self._popen = self._Popen(self)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/context.py", line 212, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/context.py", line 274, in _Popen
    return Popen(process_obj)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_spawn_posix.py", line 33, in __init__
    super().__init__(process_obj)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_fork.py", line 21, in __init__
    self._launch(process_obj)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/popen_spawn_posix.py", line 48, in _launch
    reduction.dump(process_obj, fp)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/reduction.py", line 59, in dump
    ForkingPickler(file, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function SubProcClass.__init__ at 0x10073e510>: it's not the same object as __main__.__init__

如果我们将其更改为使用fork而不是spawn

if __name__ == '__main__':
    t = ProcessInitTest(spawn=False)
    t.start_process_fail()
    for i in range(1000):
        t.do_square(i)

我们收到此错误:

Process Process-1:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 254, in _bootstrap
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
TypeError: __init__() missing 1 required positional argument: 'pipe'

但是,如果我们调用start_process方法,该方法不会在__init__目标中调用mp.Process,就像这样:

if __name__ == '__main__':
    t = ProcessInitTest(spawn=False)
    t.start_process()
    for i in range(1000):
        t.do_square(i)

它按预期工作(我们是使用spawn还是fork)。

答案 4 :(得分:2)

我无法解释为什么这也失败了,但我自己解决这个问题的方法是改变我的所有代码

from point import Point

import point

这一改变并且有效。我很想知道为什么... hth

答案 5 :(得分:2)

我将用Python2.7中的简单Python类演示问题:

In [13]: class A: pass  
In [14]: class B: pass

In [15]: A
Out[15]: <class __main__.A at 0x7f4089235738>

In [16]: B
Out[16]: <class __main__.B at 0x7f408939eb48>

In [17]: A.__name__ = "B"

In [18]: pickle.dumps(A)
---------------------------------------------------------------------------
PicklingError: Can't pickle <class __main__.B at 0x7f4089235738>: it's not the same object as __main__.B

显示此错误是因为我们正在尝试转储A,但是因为我们将其名称更改为引用另一个对象“ B”,所以pickle实际上与要转储的对象-类A或B混淆。非常聪明,他们已经对此行为进行了检查。

解决方案: 检查您要转储的对象是否与另一个对象具有冲突的名称。

我已经通过下面的ipython和ipdb演示了上述情况的调试:

PicklingError: Can't pickle <class __main__.B at 0x7f4089235738>: it's not the same object as __main__.B

In [19]: debug
> /<path to pickle dir>/pickle.py(789)save_global()
    787                 raise PicklingError(
    788                     "Can't pickle %r: it's not the same object as %s.%s" %
--> 789                     (obj, module, name))
    790
    791         if self.proto >= 2:

ipdb> pp (obj, module, name)               **<------------- you are trying to dump obj which is class A from the pickle.dumps(A) call.**
(<class __main__.B at 0x7f4089235738>, '__main__', 'B')
ipdb> getattr(sys.modules[module], name)   **<------------- this is the conflicting definition in the module (__main__ here) with same name ('B' here).**
<class __main__.B at 0x7f408939eb48>

我希望这可以节省一些麻烦!阿迪奥斯!!

答案 6 :(得分:2)

由于基于声誉的限制,我无法发表评论,但 Salim Fahedy 的答案和遵循调试路径使我能够确定此错误的原因,即使使用 dill 而不是pickle: 在幕后,dill 还访问了 dill 的一些功能。在 pickle._Pickler.save_global() 中发生了 import。在我看来,这更像是一种“黑客”而不是真正的解决方案,因为只要您尝试腌制的实例的类不是从类所在的包的最低级别导入,这种方法就会失败。抱歉解释不好,也许例子更合适:

以下示例将失败:

from oemof import solph

...
(some code here, giving you the object 'es')
...

model = solph.Model(es)
pickle.dump(model, open('file.pickle', 'wb))

它失败了,因为虽然您可以使用 solph.Model,但例如该类实际上是 oemof.solph.models.Modelsave_global() 解决了这个问题(或将它传递给 save_global() 之前的某个函数),但随后从 Model 导入 oemof.solph.models 并抛出错误,因为它不是同一个导入作为 from oemof import solph.Model(或类似的东西,我不是 100% 确定工作原理)。

以下示例将起作用:

from oemof.solph.models import Model

...
some code here, giving you the object 'es')
...

model = Model(es)
pickle.dump(model, open('file.pickle', 'wb'))

它起作用了,因为现在 Model 对象是从同一个地方导入的,pickle._Pickler.save_global() 从中导入了比较对象 (obj2)。

长话短说:酸洗对象时,请确保从尽可能低的级别导入类。

添加:这似乎也适用于存储在您要腌制的类实例的属性中的对象。例如,如果 model 有一个属性 es,它本身就是类 oemof.solph.energysystems.EnergySystem 的一个对象,我们需要将它导入为:

from oemof.solph.energysystems import EnergySystem

es = EnergySystem()

答案 7 :(得分:1)

我的问题是我在文件中定义了两次具有相同名称的函数。所以我想它对要腌的是哪一种感到困惑。

答案 8 :(得分:0)

我也发生了同样的事情

重新启动内核对我有用

答案 9 :(得分:0)

我在调试(Spyder)时遇到了同样的问题。如果运行该程序,一切正常。但是,如果我开始调试,则会遇到picklingError。

但是,一旦我在“运行每个文件的配置”(快捷方式:ctrl + F6)中选择了“ 在专用控制台中执行”选项,一切就会按预期正常运行。我不确切知道它是如何适应的。

注意:在我的脚本中,我有很多类似的输入内容

from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import os, sys, re, math

我的基本理解是,由于星号(*),我遇到了picklingError。