【问题标题】:Python - Pickle init takes 4 arguments - 1 givenPython - Pickle init 需要 4 个参数 - 1 个给定
【发布时间】:2015-06-08 00:43:14
【问题描述】:

每当我尝试加载腌制对象时,都会收到此错误:

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "renpy/common/00action_file.rpy", line 328, in __call__
    renpy.load(fn)
TypeError: __init__() takes exactly 4 arguments (1 given)

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "renpy/common/_layout/screen_main_menu.rpym", line 29, in script
    $ ui.interact()
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/ast.py", line 785, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/python.py", line 1382, in py_exec_bytecode
    exec bytecode in globals, locals
  File "renpy/common/_layout/screen_main_menu.rpym", line 29, in <module>
    $ ui.interact()
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/ui.py", line 247, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/core.py", line 2149, in interact
    repeat, rv = self.interact_core(preloads=preloads, **kwargs)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/core.py", line 2750, in interact_core
    rv = root_widget.event(ev, x, y, 0)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/layout.py", line 846, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/layout.py", line 846, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/layout.py", line 846, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/screen.py", line 626, in event
    rv = self.child.event(ev, x, y, st)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/layout.py", line 846, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/layout.py", line 846, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/layout.py", line 846, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/behavior.py", line 762, in event
    return handle_click(self.clicked)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/behavior.py", line 705, in handle_click
    rv = run(action)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/display/behavior.py", line 274, in run
    return var(*args, **kwargs)
  File "renpy/common/00action_file.rpy", line 328, in __call__
    renpy.load(fn)
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/loadsave.py", line 573, in load
    roots, log = loads(location.load(filename))
  File "/home/digiholic/workspace/SummonerSweetheart-0.9-all/renpy/loadsave.py", line 51, in loads
    return pickle.loads(s)
  File "/home/tom/ab/x64lucid-deps/install/lib/python2.7/pickle.py", line 1382, in loads
  File "/home/tom/ab/x64lucid-deps/install/lib/python2.7/pickle.py", line 858, in load
  File "/home/tom/ab/x64lucid-deps/install/lib/python2.7/pickle.py", line 1133, in load_reduce
TypeError: __init__() takes exactly 4 arguments (1 given)

Linux-3.11.0-26-generic-x86_64-with-debian-wheezy-sid
Ren'Py 6.18.3.761
Summoner Sweetheart 0.9

我目前正在使用 Renpy,一个 pygame 框架。游戏加载并保存良好,直到我达到加载我编码的外部对象的地步。加载该对象后,pickle 可以很好地保存游戏状态,但无法加载它,给我上面的错误。

我知道没有什么可做的,但这个错误太离谱了,我什至不知道问题代码在哪里可能

【问题讨论】:

  • 在 load.reduce() 中你必须创建一个新对象,并且你没有给它足够的参数。
  • load.reduce() 在哪里?
  • 你能贴出引发错误的代码吗?
  • traceback里面的代码都是外部库,没有一个是我自己写的代码。我不知道我编写的代码中的哪个对象导致了错误,而且它太多了,无法全部发布。有什么办法可以找出哪个对象的 init 方法抛出了错误?

标签: python save pygame pickle renpy


【解决方案1】:

您没有正确使用__reduce__。见这里:https://docs.python.org/2/library/pickle.html#object.reduce。对于类,您可以返回要传递给__init__classargs 的元组。有关示例,请参见此处https://github.com/uqfoundation/mystic/blob/6bfbc46f9094f96deae020074d7bdad2a43d91d6/mystic/monitors.py#L298。您还可以使用 __setstate__ 方法来实现更复杂的类行为。

小例子:

>>> class Foo(object):
...   def __init__(self, x, y, z):
...     self.x = x
...     self.y = y
...     self.z = z
...   def __reduce__(self):
...     return (self.__class__, (self.x, self.y, self.z))
...   f = lambda x:x
... 
>>> f = Foo(1,2,3)
>>> 
>>> import pickle
>>> _f = pickle.loads(pickle.dumps(f))
>>> _f.x, _f.y, _f.z
(1, 2, 3)
>>> 

但是,如果您有很多不可提取的项目,通常最简单的做法是使用更好的序列化程序,例如 dill(参见此处:https://github.com/uqfoundation/dill

【讨论】:

  • 我减少了我定义的每个类,但仍然得到相同的错误。有什么方法可以让错误告诉我哪个对象的初始化失败?
  • 首先,请注意您必须使用__reduce__ 提供所有参数,并且不能使用关键字参数(即x=4)。其次,您可以做一些愚蠢的事情,并将日志记录/打印调用插入到__reduce__'/'__init__/__setstate__,这样如果您无法从回溯中分辨出来,您就可以查看运行了哪些代码块。
  • 当你说我不能使用关键字参数时,这是否意味着我根本不能提供它们,或者我不能给它们一个默认值?就像我有一个关键字参数 directory = "/",并将其存储为 self.directory,我可以在 reduce 中传递 self.directory 吗?
  • 您正在传递一个元组args,它必须与self.__class____init__ 调用中的参数完全匹配。在__reduce__ 中,尝试按照__init__ 指定的确切顺序传递所有参数,不要依赖使用的任何默认值(kwds)。
  • 不,__reduce__dump 上被调用。但是,如果 __reduce__ 在我的回答中返回一个元组,则在 load 上调用 __init__。您可以通过__init__ 中的打印来检查哪个负载有效。
【解决方案2】:

我遇到了同样的问题。问题在于字节对象在 python 中是如何工作的。

我不知道真正的问题出在哪里,但是如果您自己将该腌制对象打印为字节字符串 (b'blahblah') 并将其直接提供给pickle.loads(b'blahblah'),您会得到同样的错误。

有些对象似乎不是这样工作的,它们不能被序列化、保存然后再反序列化(可能是因为它们的依赖关系或其他原因)。

对于那些想要使用pickle 转储对象的人,我的建议是避免使用它。
这不值得你花时间。

  1. 只需保存必要的属性,然后再使用其构造函数从这些值重新创建该对象。
  2. 或者您可以使用ORM 工具为您管理此问题。

希望这可以节省一些人的时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 2012-03-07
    • 1970-01-01
    相关资源
    最近更新 更多