菜单

Argument Clinic

相关源文件

Argument Clinic 是 CPython 中的一个代码生成工具,它自动化了 C 扩展模块的参数解析代码的创建。它减少了样板代码,确保了代码的一致性,并有助于维护 Python 的 C API 文档和实现之间的兼容性。

有关测试 C 扩展(包括通过 Argument Clinic 创建的扩展)的信息,请参阅 C 扩展测试

概述

使用 CPython 的 C API 编写正确的参数解析代码是冗长、易错且繁琐的。Argument Clinic 通过提供一种领域特定语言 (DSL) 来解决这个问题,该语言允许开发人员直接在 C 源文件中以类似 Python 的语法指定函数签名。然后,该工具会生成适当的参数解析代码、文档字符串和函数原型。

来源:Tools/clinic/clinic.py1-11 Tools/clinic/libclinic/app.py37-106

基本用法

C代码中的Argument Clinic块示例如下:

clinic工具会处理这些块并为以下内容生成相应的C代码:

  • 参数解析
  • 类型检查
  • 默认值处理
  • 文档字符串
  • 方法定义

来源:Tools/clinic/libclinic/dsl_parser.py246-1117 Tools/clinic/libclinic/block_parser.py16-38

架构

Argument Clinic 包含几个相互关联的组件,它们协同工作以解析函数规范并生成 C 代码

来源:Tools/clinic/libclinic/function.py23-310 Tools/clinic/libclinic/converter.py61-565 Tools/clinic/libclinic/parse_args.py17-941

核心组件

块解析器

块解析器从源文件中提取 Argument Clinic 块,识别输入部分和任何先前生成的代码。

来源:Tools/clinic/libclinic/block_parser.py16-257

DSL 解析器

DSL 解析器解释 Argument Clinic 语法,处理

  • 模块和类定义
  • 函数声明
  • 带类型和默认值的参数规范
  • 函数属性,如静态方法和类方法

来源:Tools/clinic/libclinic/dsl_parser.py246-1117

函数表示

函数对象存储

  • 函数名称和完整路径
  • 参数及其属性
  • 返回类型信息
  • 文档字符串
  • 函数种类(方法、静态方法、类方法等)

来源:Tools/clinic/libclinic/function.py82-179

参数表示

参数对象存储

  • 名称和 Python 类型注解
  • C 类型信息
  • 默认值
  • 参数种类(仅限位置、仅限关键字等)
  • 文档字符串
  • 转换器信息

来源:Tools/clinic/libclinic/function.py182-240

类型转换系统

Argument Clinic 的一个关键部分是其类型转换系统,该系统负责在 Python 对象和 C 类型之间进行转换。

来源:Tools/clinic/libclinic/converter.py61-565 Tools/clinic/libclinic/converters.py20-1210 Tools/clinic/libclinic/return_converters.py44-152

转换器类型

内置转换器处理常见的 Python 类型

  • bool: 转换为 C int (0 或 1)
  • int: 转换为 C int 并进行范围检查
  • str: 转换为 C const char*
  • float: 转换为 C double
  • bytes: 转换为 C char* 和长度
  • object: 直接传递 Python 对象

专用转换器

  • self_converter: 处理方法的隐式第一个参数
  • defining_class_converter: 处理类方法的类参数

来源:Tools/clinic/libclinic/converters.py20-1210

代码生成

代码生成过程为每个函数创建了几个组件

来源:Tools/clinic/libclinic/parse_args.py193-941 Tools/clinic/libclinic/codegen.py18-73

代码生成过程

对于每个函数,Argument Clinic 会生成:

  1. 文档字符串定义:包含 Python 文档字符串的 C 字符串
  2. 解析器原型:解析器函数的函数声明
  3. 解析器实现:使用 PyArg_Parse* 来提取和验证参数的代码
  4. 实现原型:实现函数的声明
  5. 方法定义:模块方法表中的条目

来源:Tools/clinic/libclinic/parse_args.py134-191 Tools/clinic/libclinic/clanguage.py72-396

参数处理

Argument Clinic 支持各种参数类型和功能

参数种类

  • 仅限位置:必须按位置指定的参数(由 / 表示)
  • 位置或关键字:可以通过位置或关键字指定的参数
  • 仅限关键字:必须按关键字指定的参数(由 * 表示)
  • 可变位置:收集剩余的位置参数(由 *args 表示)

特殊功能

  • 可选组:必须一起指定的参数组
  • 默认值:未指定时具有默认值的参数
  • 类型转换器:参数类型的自动验证和转换
  • 参数文档字符串:单个参数的文档

来源:Tools/clinic/libclinic/function.py182-240 Tools/clinic/libclinic/parse_args.py217-299

调用约定

Argument Clinic 根据参数类型支持不同的调用约定

  1. METH_NOARGS:不接受参数的函数
  2. METH_O:接受单个参数的函数
  3. METH_VARARGS:接受位置参数的函数
  4. METH_KEYWORDS:接受关键字参数的函数
  5. METH_FASTCALL:位置参数的优化调用约定
  6. METH_FASTCALL | METH_KEYWORDS:关键字参数的优化调用约定

该工具根据函数签名自动选择最有效的调用约定。

来源:Tools/clinic/libclinic/function.py153-167 Tools/clinic/libclinic/parse_args.py263-287

示例

下面是一个使用 Argument Clinic 的函数定义的简化示例

来源: Lib/test/clinic.test.c13-69 Modules/_testclinic.c107-123

实现细节

校验和系统

Argument Clinic 使用校验和来检测何时需要更新生成的代码,确保规范的更改能够正确地更新生成的代码。

/*[clinic end generated code: output=checksumvalue input=checksumvalue]*/

来源: Tools/clinic/libclinic/utils.py32-36

目标系统

该工具支持生成输出的不同目标

  • buffer:内存缓冲区,用于文本
  • file:外部文件,用于较大的输出
  • suppress:丢弃输出
  • block:插入回原始文件

来源: Tools/clinic/libclinic/app.py108-155

预设系统

预设配置输出的各个部分发送到哪里

  • block:默认预设,所有内容都在块中
  • file:将大部分输出放入外部文件
  • buffer:将输出放入缓冲区以供进一步处理

来源: Tools/clinic/libclinic/app.py39-82

与 CPython 集成

Argument Clinic 与 CPython 的构建过程深度集成

来源: Tools/clinic/clinic.py1-11 Tools/clinic/libclinic/cli.py49-114

Argument Clinic 的优点

  1. 减少样板代码:消除重复的参数解析代码
  2. 提高一致性:确保代码库中参数处理的一致性
  3. 更好的文档:自动生成和维护文档字符串
  4. 错误预防:在生成时捕获参数处理中的错误
  5. 可维护性:更容易地修改函数签名而不会出错
  6. 性能优化:自动选择最高效的调用约定

来源: Tools/clinic/libclinic/app.py37-82

命令行用法

Argument Clinic 可以直接在源文件上运行

python -m clinic module.c

选项包括:

  • --limited-capi:生成与有限 C API 兼容的代码
  • --output:指定输出文件
  • --force:强制重新生成块

来源: Tools/clinic/clinic.py1-11 Tools/clinic/libclinic/cli.py124-202

高级特性

有限 C API 支持

Argument Clinic 可以生成与 Python 的有限 C API 兼容的代码,该 API 为不同 Python 版本之间的二进制兼容性提供了保证。

来源: Tools/clinic/libclinic/parse_args.py324-332

临界区

支持生成带有临界区以实现线程安全的代码。

来源: Tools/clinic/libclinic/dsl_parser.py297-298 Tools/clinic/libclinic/function.py112

自定义转换器

开发人员可以定义自定义转换器来处理专门的类型。

来源: Tools/clinic/libclinic/converter.py30-40 Tools/clinic/libclinic/dsl_parser.py287-288

结论

Argument Clinic 是 CPython 开发生态系统中至关重要的工具,它通过自动化参数解析中容易出错的方面,使得 C 扩展代码更易于维护和更可靠。它弥合了 Python 用户友好界面与 C 的底层实现之间的差距,确保了文档字符串和实现保持同步。