74

这是我今天在 <a href"http://filmmaster.com">filmmaster.com 遇到的错误:

PicklingError: Can't pickle <class
'decimal.Decimal'>: it's not the same
object as decimal.Decimal

这到底是什么意思?它似乎没有多大意义......它似乎与django缓存有关。您可以在此处查看整个回溯:

Traceback (most recent call last):

 File
"/home/filmaster/django-trunk/django/core/handlers/base.py",
line 92, in get_response    response =
callback(request, *callback_args,
**callback_kwargs)

 File
"/home/filmaster/film20/film20/core/film_views.py",
line 193, in show_film   
workflow.set_data_for_authenticated_user()

 File
"/home/filmaster/film20/film20/core/film_views.py",
line 518, in
set_data_for_authenticated_user   
object_id = self.the_film.parent.id)

 File
"/home/filmaster/film20/film20/core/film_helper.py",
line 179, in get_others_ratings   
set_cache(CACHE_OTHERS_RATINGS,
str(object_id) + "_" + str(user_id),
userratings)

 File
"/home/filmaster/film20/film20/utils/cache_helper.py",
line 80, in set_cache    return
cache.set(CACHE_MIDDLEWARE_KEY_PREFIX
+ full_path, result, get_time(cache_string))

 File
"/home/filmaster/django-trunk/django/core/cache/backends/memcached.py",
line 37, in set   
self._cache.set(smart_str(key), value,
timeout or self.default_timeout)

 File
"/usr/lib/python2.5/site-packages/cmemcache.py",
line 128, in set    val, flags =
self._convert(val)

 File
"/usr/lib/python2.5/site-packages/cmemcache.py",
line 112, in _convert    val =
pickle.dumps(val, 2)

PicklingError: Can't pickle <class
'decimal.Decimal'>: it's not the same
object as decimal.Decimal

Filmmaster 的源代码可以从这里下载:bitbucket.org/filmmaster/filmmaster-test

任何帮助将不胜感激。

4

12 回答 12

95

在 jupyter notebook 中运行时出现此错误。我认为问题在于我使用的是%load_ext autoreload autoreload 2. 重新启动我的内核并重新运行解决了这个问题。

于 2016-07-24T11:46:51.270 回答
32

One oddity of Pickle is that the way you import a class before you pickle one of it's instances can subtly change the pickled object. Pickle requires you to have imported the object identically both before you pickle it and before you unpickle it.

So for example:

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

will make a subtly different object (sometimes) to:

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

Try fiddling with your imports, it might correct the problem.

于 2009-09-11T21:12:22.473 回答
22

我将在 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。显然,pickle 家伙非常聪明并且他们已经对这种行为进行了检查。

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

我已经使用下面的 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>

我希望这可以避免一些头痛!再见!!

于 2018-12-20T13:46:25.283 回答
10

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

from point import Point

import point

这一改变,它奏效了。我很想知道为什么... hth

于 2017-12-24T01:25:20.700 回答
8

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)。

于 2016-10-02T00:19:12.130 回答
7

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

于 2009-12-27T01:57:05.727 回答
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.Model例如。解决了该save_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()
于 2021-06-11T11:04:21.253 回答
1

我也发生了同样的事情

重新启动内核对我有用

于 2019-09-12T20:20:29.983 回答
1

我的问题是我有一个同名的函数在一个文件中定义了两次。所以我想它对它试图腌制哪一个感到困惑。

于 2019-08-31T23:11:35.137 回答
1

我在调试(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。

于 2020-02-12T11:29:54.560 回答
0

我遇到了一个还没有人提到的问题。我有一个包含__init__文件的包,其中包括:

from .mymodule import cls

然后我的顶级代码说:

import mypkg
obj = mypkg.cls()

问题在于,在我的顶级代码中,类型似乎是mypkg.cls,但实际上是mypkg.mymodule.cls。使用完整路径:

obj = mypkg.mymodule.cls()

避免错误。

于 2021-08-17T00:04:38.937 回答
0

我在 Spyder 中遇到了同样的错误。就我而言,结果很简单。我在一个名为“Class”的文件中定义了一个名为“Class”的类。我将定义中的类名称更改为“Class_obj”。pickle.dump(Class_obj,fileh)有效,但pickle.dump(Class,fileh)在将其保存在名为“Class”的文件中时无效。

于 2021-10-11T20:27:41.813 回答