

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段，并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在 Python 中使用 AWS CDK
<a name="work-with-cdk-python"></a>

Python 是 C AWS loud Development Kit (AWS CDK) 完全支持的客户端语言，被认为是稳定的。在 Python 中使用 AWS CDK 使用熟悉的工具，包括标准 Python 实现 (CPython)、虚拟环境和 Python 包安装程序`pip`。`virtualenv`构成 AWS 构造库的模块通过 [pypi](https://pypi.org/search/?q=aws-cdk) .org 分发。Python 版本的 AWS CDK 甚至使用 Python 风格的标识符（例如，`snake_case`方法名称）。

您可以使用任何编辑器或 IDE。许多 AWS CDK 开发者使用 [Visual Studio Code（或其开源代码](https://code.visualstudio.com/)的等效代码 [VSCodium](https://vscodium.com/)），该代码通过[官方扩展](https://marketplace.visualstudio.com/items?itemName=ms-python.python)对 Python 提供了良好的支持。Python 附带的 IDLE 编辑器足以帮助您入门。 AWS CDK 的 Python 模块确实有类型提示，这对于支持类型验证的 linting 工具或 IDE 非常有用。

## 开始使用 Python
<a name="python-prerequisites"></a>

要使用 AWS CDK，你必须拥有 AWS 账户和凭证，并已安装 Node.js 和 AWS CDK Toolkit。请参阅 [AWS CDK 入门](getting-started.md)。

Python AWS CDK 应用程序需要 Python 3.9 或更高版本。如果尚未安装，请在 [python.org](https://www.python.org/) 上为您的操作系统[下载兼容版本](https://www.python.org/downloads/)。如果您运行的是 Linux，则您的系统自带兼容版本，或者您可以使用发行版的包管理器（`yum`、`apt` 等）进行安装。Mac 用户可能会对 [Homebrew](https://brew.sh/) 感兴趣，这是一款适用于 macOS 的 Linux 风格的包管理器。

**注意**  
第三方语言弃用：语言版本仅在供应商或社区共享其 EOL（生命周期终止）之前才受支持，如有更改，会另行通知。

还需要使用 Python 包安装程序 `pip` 和虚拟环境管理器 `virtualenv`。在 Windows 上安装兼容的 Python 版本需要使用这些工具。在 Linux 上，`pip` 和 `virtualenv` 可以在软件包管理器中作为单独的软件包进行提供。或者，您可以使用以下命令进行安装：

```
python -m ensurepip --upgrade
python -m pip install --upgrade pip
python -m pip install --upgrade virtualenv
```

如果遇到权限错误，请运行带有 `--user` 标志的上述命令，以便将模块安装在您的用户目录中，或者使用 `sudo` 来获取在系统范围内安装模块的权限。

**注意**  
Linux 发行版通常使用可执行文件名称 `python3` 表示 Python 3.x，使用 `python` 表示 Python 2.x 安装。有些发行版有一个可以安装的可选包，可让 `python` 命令表示 Python 3。如果失败，您可以通过在项目的主目录中编辑 `cdk.json` 来调整用于运行应用程序的命令。

**注意**  
在 Windows 上，您可能需要使用 `py` 可执行文件（[适用于 Windows 的 Python 启动器](https://docs.python.org/3/using/windows.html#launcher)）来调用 Python（和 `pip`）。除此之外，启动器还允许您轻松指定要使用的 Python 安装版本。  
如果在命令行键入 `python` 后会显示一条关于从 Windows 应用商店安装 Python 的消息，即使安装了 Windows 版本的 Python，也请打开 Windows 的“管理应用程序执行别名”设置面板并关闭 Python 的两个应用程序安装程序条目。

## 创建项目
<a name="python-newproject"></a>

您可以通过在空目录`cdk init`中调用来创建新的 AWS CDK 项目。使用 `--language` 选项并指定 `python`：

```
$ mkdir my-project
$ cd my-project
$ cdk init app --language python
```

 `cdk init` 使用项目文件夹的名称来命名项目的各种元素，包括类、子文件夹和文件。文件夹名称中的连字符都将转换为下划线。但是，名称应遵循 Python 标识符的形式；例如，名称不应以数字开头，也不应包含空格。

要使用新项目，请激活其虚拟环境。这允许将项目的依赖项安装在本地项目文件夹中，而不是全局安装。

```
$ source .venv/bin/activate
```

**注意**  
您可能会将其识别为激活虚拟环境的 Mac/Linux 命令。Python 模板包含一个批处理文件 `source.bat`，该文件允许在 Windows 上使用相同的命令。也可以使用传统的 Windows 命令 `.\venv\Scripts\activate`。  
如果您使用 AWS CDK Toolkit v1.70.0 或更早版本初始化 CDK 项目，则您的虚拟环境位于目录中，而不是。`.env` `.venv`

**重要**  
无论何时开始处理项目，都要激活该项目的虚拟环境。否则，您将无法访问安装在那里的模块，并且您安装的模块将进入 Python 全局模块目录（或将导致权限错误）。

首次激活虚拟环境后，请安装应用程序的标准依赖项：

```
$ python -m pip install -r requirements.txt
```

## 管理 AWS 构造库模块
<a name="python-managemodules"></a>

使用 Python 包安装程序安装和更新 AWS 构造库模块以供您的应用程序使用，以及您需要的其他包。`pip` `pip`还会自动安装这些模块的依赖关系。如果您的系统无法识别 `pip` 为独立命令，请将 `pip` 作为 Python 模块进行调用，如下所示：

```
$ python -m pip <PIP-COMMAND>
```

大多数 AWS CDK 结构都在。`aws-cdk-lib`实验性模块位于名称类似于 `aws-cdk.<SERVICE-NAME>.alpha` 的单独模块中。服务名称包含 *aws* 前缀。如果您不确定某个模块的名称，请[在 PyPI 上进行搜索](https://pypi.org/search/?q=aws-cdk)。例如，下面的命令安装该 AWS CodeStar 库。

```
$ python -m pip install aws-cdk.aws-codestar-alpha
```

某些服务的构造位于多个命名空间中。例如，除 `aws-cdk.aws-route53` 之外，还有另外三个 Amazon Route 53 命名空间，`aws-route53-targets`、`aws-route53-patterns` 和 `aws-route53resolver`。

**注意**  
[CDK API Reference 的 Python 版本](https://docs.aws.amazon.com/cdk/api/v2/python/index.html)也显示了包名称。

用于将 AWS 构造库模块导入 Python 代码的名称如下所示。

```
import aws_cdk.aws_s3 as s3
import aws_cdk.aws_lambda as lambda_
```

在应用程序中导入 AWS CDK 类和 AWS 构造库模块时，我们建议采用以下做法。遵循这些准则将有助于使您的代码与其他 AWS CDK 应用程序保持一致，并且更易于理解。
+ 通常，从顶层 `aws_cdk` 中导入单个类。

  ```
  from aws_cdk import App, Construct
  ```
+ 如果您需要 `aws_cdk` 中的许多类，则可以使用 `cdk` 的命名空间别名，而不是导入单个类。避免同时执行这两项操作。

  ```
  import aws_cdk as cdk
  ```
+ 通常，使用短命名空间别名导入 AWS 构造库。

  ```
  import aws_cdk.aws_s3 as s3
  ```

安装模块后，请更新项目的 `requirements.txt` 文件，其中列出了项目的依赖项。最好手动执行此操作，而不是使用 `pip freeze`。`pip freeze` 会捕获 Python 虚拟环境中安装的所有模块的当前版本，这在将项目捆绑到其他地方运行时非常有用。

但是，通常情况下，您的 `requirements.txt` 应该只列出顶级依赖项（您的应用程序直接依赖的模块），而不会列出这些库的依赖项。这种策略让更新依赖项变得更加简单。

您可以编辑 `requirements.txt` 以允许升级；只需将版本号前面的 `==` 替换为 `~=` 即可升级到更高的兼容版本，或者完全删除版本要求以指定模块的最新可用版本。

适当编辑 `requirements.txt` 以允许升级后，可以随时发出以下命令来升级项目中已安装的模块：

```
$ pip install --upgrade -r requirements.txt
```

## 在 Python 中管理依赖项
<a name="work-with-cdk-python-dependencies"></a>

在 Python 中，您可以在应用程序的 `requirements.txt` 或构造库的 `setup.py` 中输入依赖项来指定依赖项。然后使用 PIP 工具来管理依赖关系。通过以下方式之一来调用 PIP：

```
pip <command options>
python -m pip <command options>
```

`python -m pip` 调用适用于大多数系统；`pip` 要求 PIP 的可执行文件位于系统路径上。如果 `pip` 不起作用，请尝试将其替换为 `python -m pip`。

`cdk init --language python` 命令会为您的新项目创建一个虚拟环境。这样每个项目就都有自己的依赖项版本，还有一个基本 `requirements.txt` 文件。每次开始使用项目时，都必须运行 `source .venv/bin/activate` 来激活此虚拟环境。在 Windows 上，改为运行 `.\venv\Scripts\activate`

### CDK 应用程序
<a name="work-with-cdk-python-dependencies-apps"></a>

下面是一个 `requirements.txt` 示例文件。由于 PIP 不具备依赖锁定功能，我们建议您使用 == 运算符为所有依赖项指定确切的版本，如下所示。

```
aws-cdk-lib==2.14.0
aws-cdk.aws-appsync-alpha==2.10.0a0
```

使用 `pip install` 来安装模块不会自动将其添加到 `requirements.txt`。必须自己动手添加。如果要升级到依赖项的更高版本，请在 `requirements.txt` 中编辑其版本号。

要在创建或编辑 `requirements.txt` 后安装或更新项目的依赖项，请运行以下命令：

```
python -m pip install -r requirements.txt
```

**提示**  
`pip freeze` 命令以可写入文本文件的格式输出所有已安装依赖项的版本。这可以用作 `pip install -r` 的需求文件。此文件便于将所有依赖项（包括传递依赖项）固定到您测试过的确切版本。为避免以后升级软件包时出现问题，请为此使用单独的文件，例如 `freeze.txt`（不是 `requirements.txt`）。然后，在升级项目的依赖项时重新生成此文件。

### 第三方构造库
<a name="work-with-cdk-python-dependencies-libraries"></a>

在库中，依赖项在 `setup.py` 中进行指定，以便应用程序使用包时会自动下载传递依赖项。否则，每个想要使用包的应用程序都需要将您的依赖项复制到其 `requirements.txt` 中。此处显示了一个示例 `setup.py`。

```
from setuptools import setup

setup(
  name='my-package',
  version='0.0.1',
  install_requires=[
    'aws-cdk-lib==2.14.0',
  ],
  ...
)
```

要使用包进行开发，请创建或激活虚拟环境，然后运行以下命令。

```
python -m pip install -e .
```

尽管 PIP 会自动安装传递依赖项，但每个包只能安装一个副本。已选择依赖项树中指定的最高版本；应用程序对安装哪个版本的软件包始终拥有最终决定权。

## AWS Python 中的 CDK 成语
<a name="python-cdk-idioms"></a>

### 语言冲突
<a name="python-keywords"></a>

在 Python 中，`lambda`是一个语言关键字，因此您不能将其用作 Lambda 构造库模块 AWS 或 Lambda 函数的名称。对于此类冲突，Python 的惯例是在变量名称中使用尾随下划线，如 `lambda_` 所示。

按照惯例， AWS CDK 构造的第二个参数被命名。`id`在编写自己的堆栈和构造时，调用参数 `id` 会“掩盖”Python 内置函数 `id()`，该函数用于返回对象的唯一标识符。此函数并不常用，但是如果您在构造中碰巧需要它，请重命名该参数，例如 `construct_id`。

### 参数和属性
<a name="python-props"></a>

所有 C AWS onstruct Library 类都使用三个参数进行实例化：定义构造的*作用域*（构造树中的父级）、*id* 和 *props*（构造函数用来配置其创建的资源的一 key/value 组对）。其他类和方法也使用“属性捆绑包”模式作为参数。

 *scope* 和 *id* 应始终作为位置参数而不是关键字参数进行传递，因为如果构造接受名为 *scope* 或 *id* 的属性，其名称就会改变。

在 Python 中，props 表示为关键字参数。如果参数包含嵌套数据结构，则使用在实例化时采用其自身关键字参数的类来表示这些结构。同样的模式也适用于采用结构化参数的其他方法调用。

例如，在 Amazon S3 存储桶的 `add_lifecycle_rule` 方法中，`transitions` 属性是 `Transition` 实例的列表。

```
bucket.add_lifecycle_rule(
  transitions=[
    Transition(
      storage_class=StorageClass.GLACIER,
      transition_after=Duration.days(10)
    )
  ]
)
```

扩展某个类或重写某种方法时，您可能希望接受父类无法理解的其他参数，以满足自己的目的。在这种情况下，您应该使用 \$1\$1kwargs 习语来接受您不在意的参数，并使用仅限关键字的参数来接受您感兴趣的参数。在调用父级的构造函数或重写的方法时，请仅传递所需的参数（通常只是 \$1\$1kwargs）。传递父类或方法不需要的参数会导致错误。

```
class MyConstruct(Construct):
    def __init__(self, id, *, MyProperty=42, **kwargs):
        super().__init__(self, id, **kwargs)
        # ...
```

Future 版本的 AWS CDK 可能会巧合地添加一个新属性，其名称是你用于自己的财产。这不会为您的构造或方法的用户带来任何技术问题（因为您的属性不会“向上沿链”传递，所以父类或重写的方法只会使用默认值），但可能会造成困惑。您可以对属性进行命名来避免这个潜在问题，这样它们就明确属于您的构造。如果有许多新属性，请将其捆绑到一个适当命名的类中，然后将其用作单个关键字参数进行传递。

### 缺失值
<a name="python-missing-values"></a>

 AWS CDK `None` 用来表示缺失或未定义的值。使用 \$1\$1kwargs 时，如果未提供属性，则使用词典的 `get()` 方法提供默认值。避免使用 `kwargs[…​]`，因为这会引发缺失值的 `KeyError`。

```
encrypted = kwargs.get("encrypted")         # None if no property "encrypted" exists
encrypted = kwargs.get("encrypted", False)  # specify default of False if property is missing
```

某些 AWS CDK 方法（例如`tryGetContext()`获取运行时上下文值）可能会返回`None`，您需要明确检查这些方法。

### 使用接口
<a name="python-interfaces"></a>

Python 不像其他一些语言那样具有接口功能，不过其确实有类似的[抽象基类](https://docs.python.org/3/library/abc.html)。（如果你不熟悉界面，维基百科[有一个很好的介绍](https://en.wikipedia.org/wiki/Interface_(computing)#In_object-oriented_languages)。） TypeScript，实现 AWS CDK 所用的语言，确实提供了接口，而构造和其他 AWS CDK 对象通常需要一个附属于特定接口的对象，而不是从特定类继承的对象。因此，作为 [JSI](https://github.com/aws/jsii) I 层的一部分， AWS CDK 提供了自己的接口功能。

要表示一个类实现了特定的接口，可以使用 `@jsii.implements` 装饰器：

```
from aws_cdk import IAspect, IConstruct
import jsii

@jsii.implements(IAspect)
class MyAspect():
    def visit(self, node: IConstruct) -> None:
        print("Visited", node.node.path)
```

### 类型陷阱
<a name="python-type-pitfalls"></a>

Python 使用动态类型，其中所有变量都可以表示任何类型的值。参数和返回值可以用类型进行注释，但这些是“提示”，不会强制执行。这意味着在 Python 中，很容易将错误类型的值传递给 AWS CDK 构造。当JSII层（在Python和 AWS CDK的 TypeScript 核心之间进行转换）无法处理意外类型时，您可能会遇到运行时错误，而不是像静态类型语言那样在构建过程中出现类型错误。

根据我们的经验，Python 程序员犯的类型错误往往属于以下类别。
+ 在构造需要容器（Python 列表或词典）的地方传递单个值，反之亦然。
+ 将与第 1 层（`CfnXxxxxx`）构造关联的类型的值传递给 L2 或 L3 构造，反之亦然。

## 防止类型错误
<a name="_preventing_type_errors"></a>

AWS CDK Python 模块包含类型注释，因此您可以在部署之前使用支持它们的工具来捕获类型错误。

### 集成集成开发环境（推荐）
<a name="_ide_integration_recommended"></a>

带有 Pylance 的 Visual Studio Code 可在你编写代码时提供实时类型检查：

1. 安装 [Pyl](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) ance 扩展程序 

1. 配置严格的类型检查`.vscode/settings.json`：

   ```
   {
     "python.languageServer": "Pylance",
     "python.analysis.typeCheckingMode": "strict"
   }
   ```

1. 现在，键入错误会立即出现，带有红色波浪线和详细的错误消息

 [PyCharm](https://www.jetbrains.com/pycharm/)还提供具有类似功能的内置类型检查。

### 命令行类型检查
<a name="_command_line_type_checking"></a>

对于 CI/CD 管道或预提交验证，请使用以下类型检查器之一：

 **MyPy （基于 Python）：**

```
pip install mypy
mypy app.py
```

 **Pyright（速度更快， JavaScript基于，引擎与 Pylance 相同）：**

```
npm install -g pyright
pyright app.py
```

### 推荐的工作流
<a name="_recommended_workflow"></a>

1. 开发过程中：使用 Pyright 或 Pylance 获得即时反馈

1. 提交之前：运行`mypy app.py`或 `pyright app.py` 

1. 在 CI/CD 中：在部署之前将类型检查作为必需的步骤