定义采用 Python 的 Lambda 函数处理程序 - AWS Lambda

定义采用 Python 的 Lambda 函数处理程序

Lambda 函数处理程序是函数代码中处理事件的方法。当调用函数时,Lambda 运行处理程序方法。您的函数会一直运行,直到处理程序返回响应、退出或超时。

本页介绍如何使用采用 Python 的 Lambda 函数处理程序,包括命名约定、有效的处理程序签名和代码最佳实践。本页还包括 Python Lambda 函数的示例,该函数接收订单信息,生成文本文件收据,然后将此文件放入 Amazon Simple Storage Service(Amazon S3)存储桶中。

示例 Python Lambda 函数代码

以下示例 Python Lambda 函数代码接收有关订单的信息,生成文本文件接收,并将此文件放入 Amazon S3 存储桶中:

例 Python Lambda 函数
import json import os import logging import boto3 # Initialize the S3 client outside of the handler s3_client = boto3.client('s3') # Initialize the logger logger = logging.getLogger() logger.setLevel("INFO") def upload_receipt_to_s3(bucket_name, key, receipt_content): """Helper function to upload receipt to S3""" try: s3_client.put_object( Bucket=bucket_name, Key=key, Body=receipt_content ) except Exception as e: logger.error(f"Failed to upload receipt to S3: {str(e)}") raise def lambda_handler(event, context): """ Main Lambda handler function Parameters: event: Dict containing the Lambda function event data context: Lambda runtime context Returns: Dict containing status message """ try: # Parse the input event order_id = event['Order_id'] amount = event['Amount'] item = event['Item'] # Access environment variables bucket_name = os.environ.get('RECEIPT_BUCKET') if not bucket_name: raise ValueError("Missing required environment variable RECEIPT_BUCKET") # Create the receipt content and key destination receipt_content = ( f"OrderID: {order_id}\n" f"Amount: ${amount}\n" f"Item: {item}" ) key = f"receipts/{order_id}.txt" # Upload the receipt to S3 upload_receipt_to_s3(bucket_name, key, receipt_content) logger.info(f"Successfully processed order {order_id} and stored receipt in S3 bucket {bucket_name}") return { "statusCode": 200, "message": "Receipt processed successfully" } except Exception as e: logger.error(f"Error processing order: {str(e)}") raise

此 文件包含以下代码部分:

  • import 数据块:使用此数据块来包含 Lambda 函数所需的库。

  • SDK 客户端和记录程序的全局初始化:在处理程序之外包括初始化代码可利用执行环境重用来提高函数性能。请参阅Python Lambda 函数的代码最佳实践,了解更多信息。

  • def upload_receipt_to_s3(bucket_name, key, receipt_content): 这是一个由主 lambda_handler 函数调用的辅助函数。

  • def lambda_handler(event, context)::这是您的代码的主处理程序函数,包含主应用程序逻辑。当 Lambda 调用您的函数处理程序时,Lambda 运行时会向该函数传递两个参数,一个是包含要处理的函数的数据的事件对象,另一个是包含函数调用相关信息的上下文对象

处理程序命名约定

在创建 Lambda 函数时定义的函数处理程序名称来自以下内容:

  • Lambda 处理程序函数所在的文件名称。

  • Python 处理程序函数的名称。

在上面的示例中,如果文件名为 lambda_function.py,则处理程序将被指定为 lambda_function.lambda_handler。这是为您使用 Lambda 控制台创建的函数所指定的默认处理程序名称。

如果您在控制台中使用不同的文件名或函数处理程序名称创建函数,则必须编辑默认处理程序名称。

更改函数处理程序名称(控制台)
  1. 打开 Lambda 控制台的函数页面,然后选择一个函数。

  2. 选择节点选项卡。

  3. 向下滚动到运行时设置窗格并选择编辑

  4. 处理程序中,输入函数处理程序的新名称。

  5. 选择保存

使用 Lambda 事件对象

当 Lambda 调用函数时,它会将事件对象参数传递给函数处理程序。JSON 对象是 Lambda 函数的最常用事件格式。在上一部分的代码示例中,该函数需要以下格式的输入:

{ "Order_id": "12345", "Amount": 199.99, "Item": "Wireless Headphones" }

如果您的函数被其他 AWS 服务调用,则输入事件也是 JSON 对象。事件对象的确切格式由调用函数的服务决定。要查看特定服务的事件格式,请参阅 使用来自其 AWS 他服务的事件调用 Lambda 章节中的相应页面。

如果输入事件采用 JSON 对象的形式,则 Lambda 运行时将该对象转换为 Python 字典。要将输入 JSON 中的值分配给代码中的变量,请使用标准的 Python 字典方法,如示例代码所示。

您也可以将数据作为 JSON 数组或任何其他有效的 JSON 数据类型传递给函数。下表就 Python 运行时如何转换这些 JSON 类型进行了定义。

JSON 数据类型 Python 数据类型
object 字典(dict
array 列表(list
数字 整数(int)或浮点数(float
字符串 字符串(str
布尔值 布尔值(bool
null NoneType(NoneType

访问和使用 Lambda 上下文对象

Lambda 上下文对象包含有关函数调用和执行环境的信息。Lambda 会在被调用时自动将上下文对象传递给函数。您可以使用上下文对象输出有关函数调用的信息,以便进行监控。

上下文对象是在 Lambda 运行时接口客户端中定义的 Python 类。要返回任何上下文对象属性的值,请对上下文对象使用相应的方法。例如,以下代码段将 aws_request_id 属性的值(调用请求的标识符)分配给名为 request 的变量。

request = context.aws_request_id

要了解有关使用 Lambda 上下文对象的更多信息并查看可用方法和属性的完整列表,请参阅 使用 Lambda 上下文对象检索 Python 函数信息

Python 处理程序的有效处理程序签名

在 Python 中定义处理程序函数时,该函数必须采用两个参数。这些参数中的第一个是 Lambda 事件对象,第二个是 Lambda 上下文对象。按照惯例,这些输入参数通常命名为 eventcontext,但您可以给它们指定任何您想要的姓名。如果您使用单个输入参数声明处理程序函数,则 Lambda 在尝试运行您的函数时将引发错误。在 Python 中声明处理程序函数的最常用方法如下:

def lambda_handler(event, context):

您也可以在函数声明中使用 Python 类型提示,如以下示例所示:

from typing import Dict, Any def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:

要对其他 AWS 服务生成的事件和上下文对象使用特定的 AWS 类型,请将 aws-lambda-typing 程序包添加到函数的部署包中。您可以通过运行 pip install aws-lambda-typing 将此库安装到您的开发环境中。以下代码段演示如何使用特定于 AWS 的类型提示。在此示例中,预期事件是 Amazon S3 事件。

from aws_lambda_typing.events import S3Event from aws_lambda_typing.context import Context from typing import Dict, Any def lambda_handler(event: S3Event, context: Context) -> Dict[str, Any]:

不能将 Python async 函数类型用于处理程序函数。

返回值

(可选)处理程序可返回值,该值必须是 JSON 可序列化的。常见的返回类型包括 dictliststrintfloatbool

返回值所发生的状态取决于调用函数的调用类型服务。例如:

  • 如果您使用 RequestResponse 调用类型同步调用 Lambda 函数,Lambda 会将 Python 函数调用的结果返回到调用 Lambda 函数的客户端(在对调用请求的 HTTP 响应中,序列化为 JSON)。例如,AWS Lambda 控制台使用 RequestResponse 调用类型,因此当您使用控制台调用函数时,控制台将显示返回的值。

  • 如果处理程序返回 json.dumps 无法序列化的对象,则运行时返回错误。

  • 如果处理程序返回 None(就像不具有 return 语句的 Python 函数隐式执行的那样),则运行时返回 null

  • 如果您使用 Event 调用类型(一种异步调用),则该值将被丢弃。

在示例代码中,处理程序返回以下 Python 字典:

{ "statusCode": 200, "message": "Receipt processed successfully" }

Lambda 运行时会序列化此字典,并将其作为 JSON 字符串返回到调用该函数的客户端。

注意

在 Python 3.9 及更高版本中,Lambda 在错误响应中包含调用的 requestId。

在处理程序中使用 AWS SDK for Python (Boto3)

通常,您将使用 Lambda 函数与其他 AWS 服务 和资源进行交互。与此类资源最简单的交互方法是使用 AWS SDK for Python (Boto3)。所有支持的 Lambda Python 运行时都包含适用于 Python 的 SDK 的一个版本。但是,如果您的代码需要使用 SDK,强烈建议您将其包含在函数的部署包中。在部署包中包含 SDK 可以让您完全控制依赖项,并降低与其他库发生版本不一致问题的风险。要了解更多信息,请参阅 Python 中的运行时系统依赖项向后兼容性

要在 Lambda 函数中使用适用于 Python 的 SDK,请在函数代码开头的导入块中添加以下语句:

import boto3

使用 pip install 命令将 boto3 库添加到函数的部署包中。有关如何向 .zip 部署包添加依赖项的详细说明,请参阅 创建含依赖项的 .zip 部署包。要详细了解如何向部署为容器映像的 Lambda 函数添加依赖项,请参阅 从基本映像创建映像从备用基本映像创建映像

在代码中使用 boto3 时,无需提供任何凭证即可初始化客户端。例如,在示例代码中,我们使用以下代码行初始化 Amazon S3 客户端:

# Initialize the S3 client outside of the handler s3_client = boto3.client('s3')

使用 Python,Lambda 会自动创建带有凭证的环境变量。boto3 SDK 会在初始化期间检查函数的环境变量中是否存在这些凭证。

评估环境变量

在处理程序代码中,您可以使用 os.environ.get 方法引用环境变量。在示例代码中,我们使用以下代码行引用已定义的 RECEIPT_BUCKET 环境变量:

# Access environment variables bucket_name = os.environ.get('RECEIPT_BUCKET')

请勿遗忘在代码开头的导入块中包含一条 import os 语句。

Python Lambda 函数的代码最佳实践

在构建 Lambda 函数时,请遵循以下列表中的指南,采用最佳编码实践:

  • 从核心逻辑中分离 Lambda 处理程序。这样您可以创建更容易进行单元测试的函数。例如,在 Python 中,如下所示:

    def lambda_handler(event, context): foo = event['foo'] bar = event['bar'] result = my_lambda_function(foo, bar) def my_lambda_function(foo, bar): // MyLambdaFunction logic here
  • 控制函数部署包中的依赖项。AWS Lambda 执行环境包含许多库。对于 Node.js 和 Python 运行时,其中包括 AWS SDK。Lambda 会定期更新这些库,以支持最新的功能组合和安全更新。这些更新可能会使 Lambda 函数的行为发生细微变化。要完全控制您的函数所用的依赖项,请使用部署程序包来打包所有依赖项。

  • 将依赖关系的复杂性降至最低。首选在执行环境启动时可以快速加载的更简单的框架。

  • 将部署程序包大小精简为只包含运行时必要的部分。这样会减少调用前下载和解压缩部署程序包所需的时间。

  • 利用执行环境重用来提高函数性能。连接软件开发工具包 (SDK) 客户端和函数处理程序之外的数据库,并在 /tmp 目录中本地缓存静态资产。由函数的同一实例处理的后续调用可重用这些资源。这样就可以通过缩短函数运行时间来节省成本。

    为了避免调用之间潜在的数据泄露,请不要使用执行环境来存储用户数据、事件或其他具有安全影响的信息。如果您的函数依赖于无法存储在处理程序的内存中的可变状态,请考虑为每个用户创建单独的函数或单独的函数版本。

  • 使用 keep-alive 指令来维护持久连接。Lambda 会随着时间的推移清除空闲连接。在调用函数时尝试重用空闲连接会导致连接错误。要维护您的持久连接,请使用与运行时关联的 keep-alive 指令。有关示例,请参阅在 Node.js 中通过 Keep-Alive 重用连接

  • 使用环境变量将操作参数传递给函数。例如,您在写入 Amazon S3 存储桶时,不应对要写入的存储桶名称进行硬编码,而应将存储桶名称配置为环境变量。

  • 避免在 Lambda 函数中使用递归调用,在这种情况下,函数会调用自己或启动可能再次调用该函数的进程。这可能会导致意想不到的函数调用量和升级成本。如果您看到意外的调用量,请立即将函数保留并发设置为 0 来限制对函数的所有调用,同时更新代码。

  • Lambda 函数代码中不要使用非正式的非公有 API。对于 AWS Lambda 托管式运行时,Lambda 会定期为 Lambda 的内部 API 应用安全性和功能更新。这些内部 API 更新可能不能向后兼容,会导致意外后果,例如,假设您的函数依赖于这些非公有 API,则调用会失败。请参阅 API 参考以查看公开发布的 API 列表。

  • 编写幂等代码。为您的函数编写幂等代码可确保以相同的方式处理重复事件。您的代码应该正确验证事件并优雅地处理重复事件。有关更多信息,请参阅如何使我的 Lambda 函数具有幂等性?