首页 > 解决方案 > 调用pickeled函数时出现RecursionError

问题描述

我正在尝试运行以下代码:

import pickle

def foo():
    print("i am foo")
    
pickle_foo = pickle.dumps(foo)

def foo():
    print("i am the new foo")
    fkt = pickle.loads(pickle_foo)
    return fkt()

foo()

预期的行为将是:

i am the new foo
i am foo

实际发生的是:

RecursionError: maximum recursion depth exceeded while calling a Python object

当两个函数的名称不同时,不会发生错误,但这对我的项目来说是非常不切实际的。谁能解释一下,为什么会发生这种行为以及如何避免它(不更改函数名称)?

标签: pythonpython-3.xpickle

解决方案


pickle模块 pickles 函数基于其完全限定的名称引用。这意味着如果您的函数在代码中的某处被重新定义,然后您取消对它的腌制引用,则调用它将导致调用新定义。

来自Python文档pickle

请注意,函数(内置的和用户定义的)是通过“完全限定”名称引用而不是值来腌制的。2 这意味着只有函数名和定义函数的模块名称被腌制。函数的代码和它的任何函数属性都没有被腌制。因此,定义模块必须在 unpickling 环境中是可导入的,并且模块必须包含命名对象,否则将引发异常。

但是,您可以做的是使用inspect.getsource()检索函数的源代码,然后腌制它。这要求您的代码在文件系统的某处可用作源代码,因此导入的编译 C 代码或其他外部源代码(解释器输入、动态加载的模块)将不起作用。

当你 unpickle 时,你可以使用exec它来将它转换成一个函数并执行它。

注意:这将foo每次重新定义,因此foo不能保证调用具有相同的效果。

注意 2:exec不安全,通常不适合与外部源交互的代码。确保保护调用exec免受试图执行任意代码的潜在外部攻击。


推荐阅读