PicklingError: 无法序列化 <class 'decimal.Decimal'>: 不是与 decimal.Decimal 相同的对象

88 投票
16 回答
102493 浏览
提问于 2025-04-15 14:16

今天我在<a href="http://filmaster.com">filmaster.com</a>上遇到了这个错误:

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

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

任何帮助都将非常感谢。

16 个回答

29

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

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>

希望这能帮你省去一些麻烦!再见!!

39

Pickle 有个奇怪的地方,就是在你准备把一个类的实例保存成文件之前,导入这个类的方式可能会影响到保存下来的对象。Pickle 要求你在保存和读取这个对象时,导入的方式必须完全一样。

举个例子:

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

这样保存下来的对象(有时候)会和:

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

这样保存的对象不太一样。

你可以试着调整一下你的导入方式,可能会解决这个问题。

119

我在使用jupyter notebook的时候遇到了这个错误。我觉得问题出在我用了 %load_ext autoreloadautoreload 2。重启我的内核然后重新运行代码就解决了这个问题。

撰写回答