python - 调用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()
预期的行为将是:
- 新定义的函数“foo”被调用
- 在新函数中,旧函数被取消选中,然后调用
输出:
i am the new foo
i am foo
实际发生的是:
- 新函数 foo 被调用,然后递归调用自身,直到抛出递归错误:
RecursionError: maximum recursion depth exceeded while calling a Python object
当两个函数的名称不同时,不会发生错误,但这对我的项目来说是非常不切实际的。谁能解释一下,为什么会发生这种行为以及如何避免它(不更改函数名称)?
解决方案
pickle
模块 pickles 函数基于其完全限定的名称引用。这意味着如果您的函数在代码中的某处被重新定义,然后您取消对它的腌制引用,则调用它将导致调用新定义。
来自Python文档:pickle
请注意,函数(内置的和用户定义的)是通过“完全限定”名称引用而不是值来腌制的。2 这意味着只有函数名和定义函数的模块名称被腌制。函数的代码和它的任何函数属性都没有被腌制。因此,定义模块必须在 unpickling 环境中是可导入的,并且模块必须包含命名对象,否则将引发异常。
但是,您可以做的是使用inspect.getsource()
检索函数的源代码,然后腌制它。这要求您的代码在文件系统的某处可用作源代码,因此导入的编译 C 代码或其他外部源代码(解释器输入、动态加载的模块)将不起作用。
当你 unpickle 时,你可以使用exec
它来将它转换成一个函数并执行它。
注意:这将foo
每次重新定义,因此foo
不能保证调用具有相同的效果。
注意 2:exec
不安全,通常不适合与外部源交互的代码。确保保护调用exec
免受试图执行任意代码的潜在外部攻击。
推荐阅读
- javascript - 排序数字数组返回无效结果
- ionic-framework - 如何设置所有 Android 设备都支持我的应用程序?- 离子-v3
- vaadin - 使用 @Tag(Tag.DIV) 注释和从 Div 类扩展之间的区别
- mysql - MYSQL 丢失用户密码
- php - Laravel 通过数组循环路由
- python - IMAP 搜索地址等于不包含
- php - 如何从 ajax 检索参数到 laravel API 控制器
- android - Android Studio Profiler 的能耗
- nginx - 未指定输入文件:无法配置 NGINX 别名
- javascript - RegEx-用打开和关闭标签替换备用特殊字符