调用pickeled函数时出现递归错误

2024-04-23 22:28:11 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

预期的行为是:

  • 调用新定义的函数“foo”
  • 在新函数中,旧函数被取消标记,然后被调用
    输出:
i am the new foo
i am foo

实际情况是:

  • 调用新函数foo,然后递归调用自身,直到抛出递归错误:
RecursionError: maximum recursion depth exceeded while calling a Python object

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


1条回答
网友
1楼 · 发布于 2024-04-23 22:28:11

pickle模块根据函数的完全限定名引用对函数进行pickle。这意味着,如果您的函数在代码中的某个地方被重新定义,然后您取消对它的pickle引用,那么调用它将导致对新定义的调用

pickle上的Python docs

Note that functions (built-in and user-defined) are pickled by “fully qualified” name reference, not by value. 2 This means that only the function name is pickled, along with the name of the module the function is defined in. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised.

但是,您可以使用inspect.getsource()检索函数的源代码,并对其进行pickle。这要求您的代码可以作为文件系统中某个地方的源代码使用,因此导入的编译C代码或其他外部源(解释器输入、动态加载的模块)将无法工作

取消勾选时,可以使用exec将其转换为函数并执行

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

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

相关问题 更多 >