Python不使用def关键字时如何创建可pickle的参数固定函数
实现方案
直接使用Python标准库functools中的partial即可,不需要用def关键字定义新函数,也不会用到无法序列化的lambda,最终得到的functionB完全支持pickle序列化。
具体写法
假设你已经定义了顶层可pickle的原函数functionA,只需要按如下方式生成functionB:
from functools import partial import pickle # 原函数示例,替换成你自己的functionA实现即可 def functionA(x, y=2): return x + y # 固定y参数为3,生成目标函数 functionB = partial(functionA, y=3) # 序列化可用性测试 pickled_data = pickle.dumps(functionB) restored_functionB = pickle.loads(pickled_data) # 调用测试,输出结果为 1+3=4 print(restored_functionB(1))
效果说明
- 调用逻辑完全符合预期:执行
functionB(x)等价于执行functionA(x, y=3),和你手写def定义的functionB行为完全一致 - 序列化无异常:只要传入partial的原函数、固定参数本身可被pickle(你场景里顶层定义的
functionA、整数3都满足要求),就可以正常完成序列化/反序列化,不会出现lambda序列化时抛出的PicklingError。
原理说明
pickle序列化可调用对象时,核心是要记录对象能被全局定位到的标识(所属模块、全局作用域下的绑定名称),反序列化时靠这个标识重新导入对象完成还原。lambda是没有全局名称的匿名表达式,pickle找不到它的定义位置,自然没法序列化。
而functools.partial本身是标准库实现的类,它的实例序列化时只会存储三类信息:绑定的原函数引用、提前固定的位置参数、提前固定的关键字参数。反序列化时只要重新导入原函数,把存下来的固定参数传进去就能还原出一模一样的partial对象,天然符合pickle的序列化规则,不会有匿名函数的定位问题。
注意:如果用partial绑定的是嵌套函数、lambda这类本身不可被pickle的可调用对象,依然会序列化失败,你的场景下绑定顶层定义的普通函数
functionA完全没有问题。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

