使用dill序列化函数时报无法pickle sqlite3.Connection错误且未使用sqlite
问题根因
该报错与你编写的函数逻辑无关,你的代码本身没有引入任何sqlite相关调用,问题出在dill的默认序列化逻辑:
- dill序列化函数时,默认会扫描并保存函数关联的全局命名空间内的所有对象,用于保证反序列化后函数可正常执行
- 你当前的运行环境(多为Jupyter、IPython这类交互式环境,也可能是当前Python进程的全局作用域)存在未被销毁的
sqlite3.Connection实例,可能来自之前运行过的其他代码、第三方依赖隐式创建、调试工具内置逻辑等,你自身可能无感知 - 你编写的
test_outer包含嵌套函数test_inner,会触发dill对全局作用域的全量扫描,刚好命中无法序列化的sqlite连接对象,才抛出对应报错。
解决方案
方案1:调整dill序列化配置(最便捷)
开启byref设置,让dill仅序列化函数实际依赖的必要对象,无需扫描全量全局命名空间:
import dill def test_outer(a): def test_inner(a): return a+1 return a dill.settings['byref'] = True # 序列化正常执行 serialized_data = dill.dumps(test_outer) # 反序列化验证正常 loaded_func = dill.loads(serialized_data) print(loaded_func(5)) # 输出5,运行正常
方案2:清理环境残留对象
- 若在脚本环境运行:排查所有引入的第三方依赖,找到隐式创建sqlite连接的逻辑,使用完后手动调用
.close()关闭连接,并删除变量引用 - 若在交互式环境运行:直接重启内核即可清除所有残留的全局对象,再次执行序列化代码即可正常运行。
方案3:调整函数结构
如果不需要嵌套函数结构,将test_inner移到和test_outer同级的全局作用域,即可避免触发dill的全量全局扫描逻辑,也不会误扫到无关的sqlite连接对象。
内容的提问来源于stack exchange,提问作者skrhee
相关产品推荐
相关产品推荐

