

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 以 Python 定義 Lambda 函數處理常式
<a name="python-handler"></a>

Lambda 函數*處理常式*是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時，Lambda 會執行處理常式方法。函數會執行，直到處理常式傳回回應、結束或逾時為止。

本頁介紹了如何在 Python 中使用 Lambda 函式處理常式，包括命名慣例、有效的處理常式簽章及程式碼最佳實務。本頁還提供了一個 Python Lambda 函式範例，該函式會取得訂單的相關資訊、產生文字檔案收據，並將此檔案放入 Amazon Simple Storage Service (Amazon S3) 儲存貯體。

**Topics**
+ [

## Python Lambda 函式程式碼範例
](#python-handler-example)
+ [

## 處理常式命名慣例
](#python-handler-naming)
+ [

## 使用 Lambda 事件物件
](#python-handler-event)
+ [

## 存取和使用 Lambda 內容物件
](#python-handler-context)
+ [

## Python 處理常式的有效處理常式簽章
](#python-handler-signature)
+ [

## 傳回值
](#python-handler-return)
+ [

## 在處理常式中使用 適用於 Python (Boto3) 的 AWS SDK
](#python-handler-sdk)
+ [

## 存取環境變數
](#python-handler-env-vars)
+ [

## Python Lambda 函數的程式碼最佳實務
](#python-handler-best-practices)

## Python Lambda 函式程式碼範例
<a name="python-handler-example"></a>

以下 Python Lambda 函式程式碼範例會取得訂單的相關資訊、產生文字檔案收據，並將此檔案放入 Amazon S3 儲存貯體：

**Example 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 用戶端和記錄器的全域初始化：將初始化程式碼包含在處理常式外部，可透過重複使用[執行環境](lambda-runtime-environment.md)來提高函式效能。如需進一步了解，請參閱[Python Lambda 函數的程式碼最佳實務](#python-handler-best-practices)。
+ `def upload_receipt_to_s3(bucket_name, key, receipt_content):` 此為主要 `lambda_handler` 函式呼叫的協助程式函式。
+ `def lambda_handler(event, context):` 此為程式碼的**主要處理常式函式**，其中包含應用程式的主要邏輯。當 Lambda 調用函式處理常式時，[Lambda 執行時期](concepts-basics.md#gettingstarted-concepts-runtime)會傳遞兩個引數至該函式：其一為包含函式需處理之資料的[事件物件](#python-handler-event)，另一為包含函式調用相關資訊的[內容物件](#python-handler-context)。

## 處理常式命名慣例
<a name="python-handler-naming"></a>

建立 Lambda 函式時定義的 Lambda 函式處理常式名稱衍生自下列項目：
+ Lambda 處理常式函數所在的檔案名稱。
+ Python 處理常式函數的名稱。

在上述範例中，如果檔案名稱為 `lambda_function.py`，則處理常式會指定為 `lambda_function.lambda_handler`。這是使用 Lambda 主控台建立函式時，預設指定的處理常式名稱。

如果要在主控台中使用不同檔案名稱或函數處理常式名稱建立函數，您必須編輯預設處理常式名稱。

**變更函數處理常式名稱的方式 (主控台)**

1. 開啟 Lambda 主控台的[函數](https://console.aws.amazon.com/lambda/home#/functions)頁面，然後選擇您的函數。

1. 選擇 **程式碼** 索引標籤。

1. 向下捲動至**執行時間設定**窗格，並選擇**編輯**。

1. 在**處理常式**中，輸入函數處理常式的新名稱。

1. 選擇**儲存**。

## 使用 Lambda 事件物件
<a name="python-handler-event"></a>

當 Lambda 調用函式時，會將[事件物件](concepts-basics.md#gettingstarted-concepts-event)引數傳遞至函式處理常式。JSON 物件是 Lambda 函式最常見的事件格式。在上一節的程式碼範例中，函式預期輸入格式如下：

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

如果函式由另一個 AWS 服務調用，則輸入事件也是 JSON 物件。事件物件的確切格式取決於調用函式的服務。若要檢視特定服務的事件格式，請參閱[使用來自其他服務的事件叫用 Lambda AWS](lambda-services.md)章節中的對應頁面。

如果輸入事件採用 JSON 物件的形式，Lambda 執行時期會將物件轉換為 Python 字典。若要將輸入 JSON 中的值指派給程式碼中的變數，請如程式碼範例所示，採用標準的 Python 字典方法。

您也可以將資料作為 JSON 陣列或任何其他有效的 JSON 資料類型傳遞至函式。下表定義了 Python 執行時期如何轉換這些 JSON 類型。


| JSON 資料類型 | Python 資料類型 | 
| --- | --- | 
| object | 字典 (dict) | 
| 陣列 | 清單 (list) | 
| number | 整數 (int) 或浮點數 (float) | 
| string | 字串 (str) | 
| Boolean | 布林值 (bool) | 
| null | 空類型 (NoneType) | 

## 存取和使用 Lambda 內容物件
<a name="python-handler-context"></a>

Lambda 內容物件包含有關函式調用和執行環境的資訊。Lambda 在調用時會自動將內容物件傳遞至函式。您可以使用內容物件，基於監控目的，輸出函數調用的資訊。

內容物件是在 [Lambda 執行時期介面用戶端](https://github.com/aws/aws-lambda-python-runtime-interface-client/blob/main/awslambdaric/lambda_context.py)中定義的 Python 類別。若要傳回任何內容物件屬性的值，請使用內容物件的對應方法。例如，下列程式碼片段會將 `aws_request_id` 屬性 (調用請求的識別碼) 的值指派給名為 `request` 的變數。

```
request = context.aws_request_id
```

若要進一步了解如何使用 Lambda 內容物件，以及檢視可用方法與屬性的完整清單，請參閱[使用 Lambda 內容物件擷取 Python 函數資訊](python-context.md)。

## Python 處理常式的有效處理常式簽章
<a name="python-handler-signature"></a>

在 Python 中定義處理常式函式時，函式必須採用兩個引數。第一個引數是 Lambda [事件物件](#python-handler-event)，第二個引數是 Lambda [內容物件](#python-handler-context)。按照慣例，這些輸入引數通常命名為 `event` 和 `context`，但您可以隨意為其命名。如果您宣告的處理常式函式只有一個輸入引數，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` 函式類型用於處理常式函式。

## 傳回值
<a name="python-handler-return"></a>

處理常式可以選擇性地傳回值，且該值必須可進行 JSON 序列化。常見的傳回類型包括 `dict`、`list`、`str`、`int`、`float` 和 `bool`。

傳回值的情況取決於調用該函數的[調用類型](lambda-invocation.md)和[服務](lambda-services.md)。例如：
+ 如果使用 `RequestResponse` 調用類型[同步調用 Lambda 函式](invocation-sync.md)，Lambda 會將 Python 函式呼叫結果傳回給調用 Lambda 函式的用戶端；該結果會出現在調用請求的 HTTP 回應中，且序列化為 JSON 格式。例如，AWS Lambda 主控台使用 `RequestResponse` 調用類型。因此，當您在主控台上調用函數時，主控台即會顯示傳回值。
+ 如果處理常式傳回 `json.dumps` 無法序列化的物件，則執行時間會傳回錯誤。
+ 如果處理常式傳回 `None` (如沒有 `return` 陳述式的 Python 函數隱含作業)，則執行時間會傳回 `null`。
+ 如果使用 `Event` 調用類型 ([非同步調用](invocation-async.md))，便會捨棄該值。

在範例程式碼中，處理常式會傳回下列 Python 字典：

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

Lambda 執行時期會將此字典序列化，並將其作為 JSON 字串傳回給調用該函式的用戶端。

**注意**  
在 Python 3.9 及更高版本中，Lambda 會在錯誤回應中包含調用的請求 ID。

## 在處理常式中使用 適用於 Python (Boto3) 的 AWS SDK
<a name="python-handler-sdk"></a>

通常，您會使用 Lambda 函式與其他 AWS 服務和資源互動。與這些資源互動的最簡單方法便是使用 適用於 Python (Boto3) 的 AWS SDK。所有[支援的 Lambda Python 執行時期](lambda-runtimes.md#runtimes-supported)都包含適用於 Python 的 SDK 版本。但是，如果程式碼需要使用 SDK，強烈建議在函式的部署套件中包含該 SDK。在部署套件中包含 SDK 可讓您完全控制相依項，並降低與其他程式庫發生版本不一致問題的風險。如需進一步了解，請參閱 [Python 中的執行期相依項](python-package.md#python-package-dependencies) 和 [回溯相容性](runtimes-update.md#runtime-update-compatibility)。

若要在 Lambda 函式中使用適用於 Python 的 SDK，請將下列陳述式新增至函式程式碼開頭的 import 區塊：

```
import boto3
```

使用 `pip install` 命令將 `boto3` 程式庫新增至函式的部署套件。如需如何將相依項新增至 .zip 部署套件的詳細說明，請參閱[建立含相依項的 .zip 部署套件](python-package.md#python-package-create-dependencies)。若要進一步了解如何將相依項新增至部署為容器映像的 Lambda 函式，請參閱[從基礎映像建立映像](python-image.md#python-image-create)或[使用替代基礎映像建立映像](python-image.md#python-alt-create)。

在程式碼中使用 `boto3` 時，無需提供任憑證即可初始化用戶端。例如，在範例程式碼中，我們使用下列程式碼行來初始化 Amazon S3 用戶端：

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

對於 Python，Lambda 會自動使用憑證來建立環境變數。`boto3` SDK 會在初始化期間檢查函式的環境變數是否包含這些憑證。

## 存取環境變數
<a name="python-handler-env-vars"></a>

在處理常式程式碼中，您可以使用 `os.environ.get` 方法來引用[環境變數](configuration-envvars.md)。在範例程式碼中，我們使用下列程式碼行來引用定義的 `RECEIPT_BUCKET` 環境變數：

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

不要忘記在程式碼開頭的 import 區塊中包含 `import os` 陳述式。

## Python Lambda 函數的程式碼最佳實務
<a name="python-handler-best-practices"></a>

請遵循下列清單中的準則，在建置 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 函數行為帶來細微的變更。若要完全掌控您函式所使用的相依性，請利用部署套件封裝您的所有相依性。
+ **最小化依存項目的複雜性。**偏好更簡易的框架，其可快速在[執行環境](lambda-runtime-environment.md)啟動時載入。
+ **將部署套件最小化至執行時期所必要的套件大小。**這能減少您的部署套件被下載與呼叫前解壓縮的時間。

**請利用執行環境重新使用來改看函式的效能。**在函式處理常式之外初始化 SDK 用戶端和資料庫連線，並在本機快取 `/tmp` 目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。

若要避免叫用間洩漏潛在資料，請不要使用執行環境來儲存使用者資料、事件，或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態，請考慮為每個使用者建立個別函式或個別函式版本。

**使用 Keep-Alive 指令維持持續連線的狀態。**Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線，請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例，請參閱[在 Node.js 中重複使用 Keep-Alive 的連線](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[環境變數](configuration-envvars.md)將操作參數傳遞給您的函數。**例如，如果您正在寫入到 Amazon S3 儲存貯體，而非對您正在寫入的儲存貯體名稱進行硬式編碼，請將儲存貯體名稱設定為環境變數。

**避免在 Lambda 函數中使用遞迴調用**，其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量，當更新程式碼時，請立刻將函數的預留並行設為 `0`，以調節對函數的所有調用。

**請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API**。對於 AWS Lambda 受管執行時間，Lambda 會定期將安全性和函數更新套用至 Lambda 的內部 API。這些內部 API 更新可能是向後不相容的，這會導致意外結果，例如若您的函數依賴於這些非公有 API，則叫用失敗。請參閱 [API 參考](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)查看公開可用 API 的清單。

**撰寫等冪程式碼。**為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊，請參閱 [How do I make my Lambda function idempotent?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/) (如何讓 Lambda 函數等冪？)。