如何反序列化LazyDataframe.serialize输出的UDF并提取函数名?
解决Polars序列化UDF的反序列化与函数名提取问题
背景
Polars对LazyDataframe中的Python UDF序列化时,会经过以下流程(从源码逻辑得出):
- 使用pickle协议5序列化函数
- 用zstd级别3压缩序列化后的字节数据
- 将压缩结果做base64编码为字符串
- 最终在序列化JSON中,这个base64字符串被转换为每个字符对应的ASCII十进制数字数组
解决方案
前置依赖
先安装zstd库用于解压:
pip install zstd
方法一:直接反序列化提取函数名(信任数据源时使用)
如果确定UDF来源安全,可以直接反序列化得到函数对象后提取名称:
import pickle import base64 import zstd # 替换为你从JSON中拿到的UDF数字数组 udf_num_array = [128, 5, 149, 198, 1, ..., 134, 82, 48, 46] # 1. 将数字数组还原为base64字符串 base64_str = ''.join(chr(num) for num in udf_num_array) # 2. base64解码获取zstd压缩字节 compressed_bytes = base64.b64decode(base64_str) # 3. zstd解压得到pickle序列化的原始字节 pickle_bytes = zstd.decompress(compressed_bytes) # 4. 反序列化得到函数对象并提取名称 func = pickle.loads(pickle_bytes) print(func.__name__) # 输出示例:multiplyBy2
方法二:解析pickle字节提取函数名(安全优先,无需反序列化函数)
如果担心未知pickle数据的安全风险,可以直接解析pickle字节结构提取函数名,避免执行函数代码:
import base64 import zstd # 替换为你从JSON中拿到的UDF数字数组 udf_num_array = [128, 5, 149, 198, 1, ..., 134, 82, 48, 46] # 先还原出pickle字节数据 base64_str = ''.join(chr(num) for num in udf_num_array) compressed_bytes = base64.b64decode(base64_str) pickle_bytes = zstd.decompress(compressed_bytes) # 解析pickle结构提取函数名 # 函数引用的pickle结构中,第二个\x8c标记后跟着函数名的长度与名称 parts = pickle_bytes.split(b'\x8c') if len(parts) >= 3: func_name_length = parts[2][0] func_name = parts[2][1:1+func_name_length].decode('utf-8') print(func_name) # 输出示例:multiplyBy2
关键说明
- 两种方法都无需将整个序列化JSON反序列化为LazyDataframe,仅针对UDF的数字数组处理即可
- 方法二通过解析pickle字节结构实现,避免了反序列化可能带来的安全风险,更适合处理不可信来源的数据
内容的提问来源于stack exchange,提问作者ANEREL
相关产品推荐
相关产品推荐

