PEP 645 – 允许将可选类型写成 x?
- 作者:
- Maggie Moss <maggiebmoss at gmail.com>
- 发起人:
- Guido van Rossum <guido at python.org>
- 状态:
- 已撤回
- 类型:
- 标准跟踪
- 创建日期:
- 2020-08-25
- 决议:
- Typing-SIG 消息
摘要
本 PEP 提议为类型添加一个 ? 运算符,允许使用 x? 来代替 Optional[x]。
PEP 撤回
由 PEP 604 引入的 T|None 表示法,用于书写 Optional[T],是 T? 的一个很好的替代方案,并且不需要新的语法。
将 T? 用作 T|None 的含义,与 TypeScript 中的用法不一致,TypeScript 中的 T? 大致表示 NotRequired[T]。这种不一致很可能会让从 TypeScript 转到 Python 的开发者感到困惑。
以上代表了 typing-sig 和本 PEP 发起人的共识。
动机
类型已成为 Python 语言中一个有价值且强大的组成部分。然而,许多类型注解冗长,给使用类型注解带来了相当大的阻力。通过改进类型语法,为 Python 代码添加类型会变得更简单,并能提升 Python 用户的开发体验。
同样,一项引入 联合类型 简写语法的 PEP 已被批准并实现。
基本原理
Python 中的类型可能非常冗长,这在努力实现类型采纳时可能成为障碍。使类型更符合人体工程学,正如在 PEP 604 中对联合类型所做的那样(例如,`int | str`),将减少为新旧 Python 代码添加类型所需的精力。`Optional` 注解在部分和完全类型的 Python 代码库中都经常使用。在对 5 个类型良好的开源项目进行的小样本抽样中,平均有 7% 的注解 包含至少一个可选类型。这表明更新语法有潜力使类型更简洁,减少代码长度并提高可读性。
在类型社区中,已经 之前讨论过 简化可选类型的语法。这些讨论中的共识是 `?` 是首选运算符。Python 语法本身不支持一元 `?`,因此需要将其添加到运行时。
在 PEP 505 中曾提出将 `?` 符号添加到 Python 语法中,该 PEP 目前处于推迟状态。 PEP 505 提出了一系列
- “None 合并”二元运算符
??- “None 感知”属性访问运算符
?.(“maybe dot”)- “None 感知”索引运算符
?[](“maybe subscript”)
如果 PEP 505 未来被批准,它不会干扰本 PEP 中提出的特定于类型的 `?`。同样,由于 `?` 的所有用法在概念上都是相关的,因此在学习 Python 或进行快速视觉理解方面不会造成混淆或障碍。
提议的语法,带有后缀运算符,模仿了 C#、TypeScript 和 Swift 等其他类型化语言中存在的可选语法。这些语言的广泛采用和流行意味着 Python 开发者可能已经熟悉这种语法。
// Optional in Swift
var example: String?
// Optional in C#
string? example;
添加此语法还将遵循使用内置类型作为注解的常用模式。例如,list、dict 和 None。这将允许在 Python 代码中添加更多注解,而无需从 typing 导入。
规范
新的可选语法应被接受用于函数、变量、属性和参数注解。
# instead of
# def foo(x: Optional[int], y: Optional[str], z: Optional[list[int]): ...
def foo(x: int?, y: str?, x: list[int]?): ...
# def bar(x: list[typing.Optional[int]]): ...
def bar(x: list[int?]): ...
新的可选语法应等同于现有的 `typing.Optional` 语法。
typing.Optional[int] == int?
新的可选语法应与现有的 `typing.Optional` 语法具有相同的身份。
typing.Optional[int] is int?
它也应该等同于与 `None` 的联合。
# old syntax
int? == typing.Union[int, None]
# new syntax
int? == int | None
由于 PEP 604 中指定的新的联合语法在 isinstance 和 issubclass 中得到支持,因此新的可选语法应该在 isinstance 和 issubclass 中都得到支持。
isinstance(1, int?) # true
issubclass(Child, Super?) # true
需要实现一个新的 dunder 方法来允许对 `?` 运算符进行重载以实现其他功能。
向后兼容性
`?` 目前在 Python 语法中未使用,因此本 PEP 完全向后兼容。
参考实现
参考实现可以在 此处找到。
被拒绝的想法
讨论过的替代方案包括
- 曾考虑使用 `~` 运算符代替 `?`。
- 一个前缀运算符(
?int)。
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源:https://github.com/python/peps/blob/main/peps/pep-0645.rst