使用pickle反序列化Python函数时触发AttributeError报错求助
问题:Pickle反序列化函数时触发AttributeError(AWS Lambda环境)
我在Jupyter Notebook中编写了customer_transform函数,使用pickle将其序列化后存储到AWS S3中。当在AWS Lambda环境中从S3读取并反序列化该函数时,触发如下AttributeError:
{ "errorMessage": "Can't get attribute 'customer_transform' on <module '__main__' from '/var/runtime/bootstrap.py'>", "errorType": "AttributeError", "stackTrace": [ " File \"/var/task/on_demand_dataset_load_and_transform/handler.py\", line 14, in lambda_handler return transform_data(load_response, udf_s3_key) ", " File \"/var/task/on_demand_dataset_load_and_transform/transform_data.py\", line 26, in transform_data udf = pickle.loads(udf_bytes) " ] }
序列化代码(Jupyter Notebook中)
def customer_transform(input): # 函数实现逻辑 import pickle def serialize_func(func): return pickle.dumps(func) serialized_transform = serialize_func(customer_transform) s3_client.put_object(Body=serialized_transform, Bucket="Bucket_name", Key="key")
反序列化代码(AWS Lambda中)
udf_bytes = s3_client.get_object(Bucket="Bucket_name", Key="key")["Body"].read() downloaded_func = pickle.loads(udf_bytes)
原因分析
Pickle序列化函数时,不会存储函数的完整代码,仅记录函数名称及其所在的模块路径。在Jupyter Notebook中,直接定义的函数默认归属__main__模块;但在AWS Lambda环境中,__main__指向的是/var/runtime/bootstrap.py,该模块中不存在customer_transform的定义,因此反序列化时会触发找不到属性的错误。
解决方案
方案1:将函数放在独立模块中(推荐)
把customer_transform函数放到独立的Python模块文件(如transform_utils.py)中,序列化和反序列化时统一从该模块导入函数,确保两端模块结构一致。
- 创建模块文件
transform_utils.py
# transform_utils.py def customer_transform(input): # 函数实现逻辑
- Jupyter中的序列化代码调整
from transform_utils import customer_transform import pickle import boto3 s3_client = boto3.client('s3') serialized_transform = pickle.dumps(customer_transform) s3_client.put_object(Body=serialized_transform, Bucket="Bucket_name", Key="key")
- AWS Lambda部署准备
将transform_utils.py与Lambda的handler代码放在同一目录下打包部署,确保Lambda环境能找到该模块。反序列化代码无需修改,此时pickle会从transform_utils模块查找函数定义。
方案2:使用cloudpickle替代pickle
cloudpickle是pickle的增强版本,支持序列化不在模块顶层的函数(如Jupyter中直接定义的函数),无需依赖原模块结构。
- Jupyter中安装并使用cloudpickle序列化
!pip install cloudpickle def customer_transform(input): # 函数实现逻辑 import cloudpickle import boto3 s3_client = boto3.client('s3') serialized_transform = cloudpickle.dumps(customer_transform) s3_client.put_object(Body=serialized_transform, Bucket="Bucket_name", Key="key")
- Lambda中安装cloudpickle并反序列化
在Lambda部署包中包含cloudpickle(可通过pip install cloudpickle -t ./安装到本地目录后打包),然后修改反序列化代码:
import cloudpickle import boto3 s3_client = boto3.client('s3') udf_bytes = s3_client.get_object(Bucket="Bucket_name", Key="key")["Body"].read() downloaded_func = cloudpickle.loads(udf_bytes)
内容的提问来源于stack exchange,提问作者palash jain
相关产品推荐
相关产品推荐

