PicklingError:无法pickle <类“decimal.Decimal”>:它与decimal.Decimal 不是同一对象

发布于 2024-08-04 17:11:20 字数 1708 浏览 5 评论 0 原文

这是我今天在 filmaster.com 上遇到的错误:

PicklingError: 无法 pickle :不一样
对象为十进制。Decimal

这究竟意味着什么?似乎没有多大意义…… 它似乎与 django 缓存有关。您可以在这里看到整个回溯:

回溯(最近一次调用):

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

 文件
“/home/filmaster/film20/film20/core/film_views.py”,
show_film 中的第 193 行   
工作流.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”,
get_others_ ratings 中的第 179 行   
set_cache(CACHE_OTHERS_RATINGS,
str(object_id) + "_" + str(user_id),
用户评分)

 文件
“/home/filmaster/film20/film20/utils/cache_helper.py”,
第 80 行,在 set_cache 返回中
缓存.设置(CACHE_MIDDLEWARE_KEY_PREFIX
+ 完整路径、结果、get_time(cache_string))

 文件
“/home/filmaster/django-trunk/django/core/cache/backends/memcached.py”,
第 37 行,已设置   
self._cache.set(smart_str(key), 值,
超时或 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:无法 pickle :不一样
对象为十进制。Decimal

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

任何帮助将不胜感激。

This is the error I got today at <a href"http://filmaster.com">filmaster.com:

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

What does that exactly mean? It does not seem to be making a lot of sense...
It seems to be connected with django caching. You can see the whole traceback here:

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

And the source code for Filmaster can be downloaded from here: bitbucket.org/filmaster/filmaster-test

Any help will be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

别想她 2024-08-11 17:11:20

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

I got this error when running in an jupyter notebook. I think the problem was that I was using %load_ext autoreload autoreload 2. Restarting my kernel and rerunning solved the problem.

格子衫的從容 2024-08-11 17:11:20

Pickle 的一个奇怪之处是,在腌制某个类的实例之前导入类的方式可能会巧妙地更改腌制的对象。 Pickle 要求您在 pickle 之前和 unpickle 之前以相同的方式导入对象。

例如:

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

会(有时)创建一个略有不同的对象:

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

尝试摆弄您的导入,它可能会纠正问题。

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.

倾城花音 2024-08-11 17:11:20

我将用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>

我希望这可以避免一些麻烦!再见!

I will demonstrate the problem with simple Python classes in 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

This error is shown because we are trying to dump A, but because we changed its name to refer to another object "B", pickle is actually confused with which object to dump - class A or B. Apparently, pickle guys are very smart and they have already put a check on this behavior.

Solution:
Check if the object you are trying to dump has conflicting name with another object.

I have demonstrated debugging for the case presented above with ipython and ipdb below:

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>

I hope this saves some headaches! Adios!!

北风几吹夏 2024-08-11 17:11:20

我也无法解释为什么会失败,但我自己解决此问题的解决方案是将我的所有代码从“执行”更改

from point import Point

import point

“这一更改”,并且它有效。我很想知道为什么...hth

I can't explain why this is failing either, but my own solution to fix this was to change all my code from doing

from point import Point

to

import point

this one change and it worked. I'd love to know why... hth

你怎么敢 2024-08-11 17:11:20

您是否以某种方式重新加载(decimal),或者对decimal模块进行了monkeypatch以更改Decimal类?这是最有可能产生此类问题的两件事。

Did you somehow reload(decimal), or monkeypatch the decimal module to change the Decimal class? These are the two things most likely to produce such a problem.

最后的乘客 2024-08-11 17:11:20

通过调用 __init__ 启动使用multiprocessing 的进程可能会出现问题。这是一个演示:

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 方法,该方法不会在 mp.Process 目标中调用 __init__ ,如下所示

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

:预期(无论我们使用 spawn 还是 fork)。

There can be issues starting a process with multiprocessing by calling __init__. Here's a demo:

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

Now, with the above code, if we run this:

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

We get this error:

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__

And if we change it to use fork instead of spawn:

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

We get this error:

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'

But if we call the start_process method, which doesn't call __init__ in the mp.Process target, like this:

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

It works as expected (whether we use spawn or fork).

淡淡離愁欲言轉身 2024-08-11 17:11:20

我也遇到了同样的情况

,重新启动内核对我有用

Same happened to me

Restarting the kernel worked for me

柠檬 2024-08-11 17:11:20

由于基于声誉的限制,我无法发表评论,但是 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。例如模型。 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) 来自。

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

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

from oemof.solph.energysystems import EnergySystem

es = EnergySystem()

Due to the restrictions based upon reputation I cannot comment, but the answer of Salim Fahedy and following the debugging-path set me up to identify a cause for this error, even when using dill instead of pickle:
Under the hood, dill also accesses some functions of dill. And in pickle._Pickler.save_global() there is an import happening. To me it seems, that this is more of a "hack" than a real solution as this method fails as soon as the class of the instance you are trying to pickle is not imported from the lowest level of the package the class is in. Sorry for the bad explanation, maybe examples are more suitable:

The following example would fail:

from oemof import solph

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

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

It fails, because while you can use solph.Model, the class actually is oemof.solph.models.Model for example. The save_global() resolves that (or some function before that which passes it to save_global()), but then imports Model from oemof.solph.models and throws an error, because it's not the same import as from oemof import solph.Model (or something like that, I'm not 100% sure about the workings).

The following example would work:

from oemof.solph.models import Model

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

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

It works, because now the Model object is imported from the same place, the pickle._Pickler.save_global() imports the comparison object (obj2) from.

Long story short: When pickling an object, make sure to import the class from the lowest possible level.

Addition: This also seems to apply to objects stored in the attributes of the class-instance you want to pickle. If for example model had an attribute es that itself is an object of the class oemof.solph.energysystems.EnergySystem, we would need to import it as:

from oemof.solph.energysystems import EnergySystem

es = EnergySystem()
ゞ记忆︶ㄣ 2024-08-11 17:11:20

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

I had same problem while debugging (Spyder). Everything worked normally if run the program. But, if I start to debug I faced the picklingError.

But, once I chose the option Execute in dedicated console in Run configuration per file (short-cut: ctrl+F6) everything worked normally as expected. I do not know exactly how it is adapting.

Note: In my script I have many imports like

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

My basic understanding was, because of star (*) I was getting this picklingError.

永言不败 2024-08-11 17:11:20

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

My issue was that I had a function with the same name defined twice in a file. So I guess it was confused about which one it was trying to pickle.

ゞ花落谁相伴 2024-08-11 17:11:20

我遇到了一个尚未有人提及的问题。我有一个带有 __init__ 文件的包,除其他外,它执行以下操作:

from .mymodule import cls

然后我的顶级代码说:

import mypkg
obj = mypkg.cls()

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

obj = mypkg.mymodule.cls()

避免错误。

I had a problem that no one has mentioned yet. I have a package with a __init__ file that does, among other things:

from .mymodule import cls

Then my top-level code says:

import mypkg
obj = mypkg.cls()

The problem with this is that in my top-level code, the type appears to be mypkg.cls, but it's actually mypkg.mymodule.cls. Using the full path:

obj = mypkg.mymodule.cls()

avoids the error.

寂寞陪衬 2024-08-11 17:11:20

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

I had the same error in Spyder. Turned out to be simple in my case. I defined a class named "Class" in a file also named "Class". I changed the name of the class in the definition to "Class_obj". pickle.dump(Class_obj,fileh) works, but pickle.dump(Class,fileh) does not when its saved in a file named "Class".

慕烟庭风 2024-08-11 17:11:20

这个神奇的功能解决了上述错误,但对我来说,它结果是另一个突然出现的错误“权限被拒绝”。但是,我想这可能会帮助某人找到解决方案,所以我仍然发布该功能:

import tempfile
import time

from tensorflow.keras.models import save_model, Model

# Hotfix function
def make_keras_picklable():
    def __getstate__(self):
        model_str = ""
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            save_model(self, fd.name, overwrite=True)
            model_str = fd.read()
        d = {'model_str': model_str}
        return d

    def __setstate__(self, state):
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            fd.write(state['model_str'])
            fd.flush()
            model = load_model(fd.name)
        self.__dict__ = model.__dict__


    cls = Model
    cls.__getstate__ = __getstate__
    cls.__setstate__ = __setstate__

# Run the function
make_keras_picklable()

### create then save your model here ###

This miraculous function solves the mentioned error, but for me it turned out to another error 'permission denied' which comes out of the blue. However, I guess it might help someone find a solution so I am still posting the function:

import tempfile
import time

from tensorflow.keras.models import save_model, Model

# Hotfix function
def make_keras_picklable():
    def __getstate__(self):
        model_str = ""
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            save_model(self, fd.name, overwrite=True)
            model_str = fd.read()
        d = {'model_str': model_str}
        return d

    def __setstate__(self, state):
        with tempfile.NamedTemporaryFile(suffix='.hdf5', delete=True) as fd:
            fd.write(state['model_str'])
            fd.flush()
            model = load_model(fd.name)
        self.__dict__ = model.__dict__


    cls = Model
    cls.__getstate__ = __getstate__
    cls.__setstate__ = __setstate__

# Run the function
make_keras_picklable()

### create then save your model here ###
终陌 2024-08-11 17:11:20

建立在这些两个之上a> 答案:如果您收到 PicklingError: Can't pickle : it's not the same object as foo.Bar 形式的错误,请尝试替换 Barfoo.Bar

您可以使用此代码片段来尝试调试出现问题的地方:

from foo import Bar
import foo

print(isinstance(foo.Bar(), foo.Bar)) # True
print(isinstance(Bar(), foo.Bar)) # Sometimes True, sometimes False

Building on these two answers: if you get an error of the form PicklingError: Can't pickle <class 'foo.Bar'>: it's not the same object as foo.Bar, try replacing Bar with foo.Bar.

You can use this snippet to try and debug where things go wrong:

from foo import Bar
import foo

print(isinstance(foo.Bar(), foo.Bar)) # True
print(isinstance(Bar(), foo.Bar)) # Sometimes True, sometimes False

哭了丶谁疼 2024-08-11 17:11:20

当使用带有装饰器的工厂模式来生成我的对象时,我收到此错误:

class MyFactory:
    _constructors = {}

    @classmethod
    def register(cls, other):
        cls._constructors[other.__name__] = other

    @classmethod
    def make_from(cls, specification):
        name = specification["name"]
        kwargs = specification["kwargs"]
        return cls._constructors[name](**kwargs)


@MyFactory.register
class SomeClass:
    def __init__(self, foo=None):
        self._foo = foo


my_obj = MyFactory.make_from({"name": "SomeClass", "kwargs": {"foo": 3}})
print(type(my_obj))

这按预期工作并产生

但是,我实现了 register< /code> 装饰器不正确;我应该这样写:

def register(cls, other):
    cls._constructors[other.__name__] = other
    return other

我缺少的关键是返回装饰器中的原始类,这表明了这个错误。对于这样的类,返回的对象是实际在模块级别保存的类,在我的例子中是 None 。我一开始没有注意到这一点,因为工厂已经缓存了该类,并且我所有的代码都使用工厂来生成这些对象。由于 pickle 直接使用 sys.modules,因此只有当我尝试从损坏的工厂中 pickle 一个对象时才会出现此错误。

I got this error when using a factory pattern with a decorator to produce my objects:

class MyFactory:
    _constructors = {}

    @classmethod
    def register(cls, other):
        cls._constructors[other.__name__] = other

    @classmethod
    def make_from(cls, specification):
        name = specification["name"]
        kwargs = specification["kwargs"]
        return cls._constructors[name](**kwargs)


@MyFactory.register
class SomeClass:
    def __init__(self, foo=None):
        self._foo = foo


my_obj = MyFactory.make_from({"name": "SomeClass", "kwargs": {"foo": 3}})
print(type(my_obj))

This works as expected and yields <class '__main__.SomeClass'>

However, I implemented the register decorator incorrectly; I should have written it like so:

def register(cls, other):
    cls._constructors[other.__name__] = other
    return other

The key that I was missing was to return the original class in the decorator, which manifested with this error. In the case of a class like this, the returned object is the class that actually gets saved at the module level, which in my case was None. I didn't notice this at first, because the factory has cached the class, and all of my code was using the factory to generate these objects. Since pickle uses sys.modules directly, this error only popped up when I tried to pickle one of the objects from the broken factory.

沙沙粒小 2024-08-11 17:11:20

有同样的问题,我的问题来自装饰器,更具体地说是@lru_cache。
我建议前往 Pickle 和装饰类 (PicklingError: not相同的对象)

Had the same problem, my problem came from a decorator, more specifically @lru_cache.
I'd recommend heading to Pickle and decorated classes (PicklingError: not the same object)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文