Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 604 – 允许将联合类型写作 X | Y

作者:
Philippe PRADOS <python at prados.fr>, Maggie Moss <maggiebmoss at gmail.com>
发起人:
Chris Angelico <rosuav at gmail.com>
BDFL 委托
Guido van Rossum <guido at python.org>
讨论至:
Typing-SIG 邮件列表
状态:
最终版
类型:
标准跟踪
主题:
类型标注
创建日期:
2019年8月28日
Python 版本:
3.10
发布历史:
2019年8月28日,2020年8月5日

目录

重要

本 PEP 是一份历史文档。最新的规范文档现可在 联合类型 找到。

×

有关如何提出更改,请参阅 PEP 1

摘要

本 PEP 提议重载类型上的 | 操作符,以允许将 Union[X, Y] 写作 X | Y,并允许其出现在 isinstanceissubclass 调用中。

动机

PEP 484PEP 526 提出了一个通用语法,用于为变量、参数和函数返回值添加类型。 PEP 585 提议 在运行时暴露泛型参数。Mypy [1] 接受一种类似于以下所示的语法:

annotation: name_type
name_type: NAME (args)?
args: '[' paramslist ']'
paramslist: annotation (',' annotation)* [',']
  • 要描述一个析取(联合类型),用户必须使用 Union[X, Y]

这种语法的冗长性不利于类型的采用。

提案

受 Scala [2] 和 Pike [3] 的启发,本提案增加了操作符 type.__or__()。有了这个新操作符,可以写 int | str 而不是 Union[int, str]。除了注解之外,这个表达式的结果在 isinstance()issubclass() 中也将是有效的。

isinstance(5, int | str)
issubclass(bool, int | float)

我们也可以写 t | NoneNone | t 来代替 Optional[t]

isinstance(None, int | None)
isinstance(42, None | int)

规范

新的联合语法应被函数、变量和参数注解接受。

简化语法

# Instead of
# def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]
def f(list: List[int | str], param: int | None) -> float | str:
    pass

f([1, "abc"], None)

# Instead of typing.List[typing.Union[str, int]]
typing.List[str | int]
list[str | int]

# Instead of typing.Dict[str, typing.Union[int, float]]
typing.Dict[str, int | float]
dict[str, int | float]

现有的 typing.Union| 语法应是等价的。

int | str == typing.Union[int, str]

typing.Union[int, int] == int
int | int == int

联合中项目的顺序不影响相等性。

(int | str) == (str | int)
(int | str | float) == typing.Union[str, float, int]

可选值应与新的联合语法等效

None | t == typing.Optional[t]

应实现新的 Union.__repr__() 方法。

str(int | list[str])
# int | list[str]

str(int | int)
# int

isinstance 和 issubclass

只要联合中的项目本身是 isinstanceissubclass 的有效参数,新语法应被 isinstanceissubclass 调用接受。

# valid
isinstance("", int | str)

# invalid
isinstance(2, list[int]) # TypeError: isinstance() argument 2 cannot be a parameterized generic
isinstance(1, int | list[int])

# valid
issubclass(bool, int | float)

# invalid
issubclass(bool, bool | list[int])

不兼容的更改

在某些情况下,一些异常将不会按预期抛出。

如果元类实现了 __or__ 操作符,它将覆盖此操作符。

>>> class M(type):
...     def __or__(self, other): return "Hello"
...
>>> class C(metaclass=M): pass
...
>>> C | int
'Hello'
>>> int | C
typing.Union[int, __main__.C]
>>> Union[C, int]
typing.Union[__main__.C, int]

异议和回应

更多讨论详情,请参阅以下链接

1. 为 Union[type1, type2] 添加新操作符?

优点

  • 这种语法更具可读性,并且与其他语言(Scala 等)相似。
  • 在运行时,int|str 在 3.10 中可能会返回一个简单对象,而不是需要从导入 typing 中获取的所有内容。

缺点

  • 添加此操作符会引入 typingbuiltins 之间的依赖关系。
  • 破坏了回溯(因为 typing 可以很容易地回溯,但核心 types 不行)。
  • 如果 Python 本身不需要更改,我们仍然需要在 mypy、Pyre、PyCharm、Pytype 以及其他一些工具中实现它(这是一个微小的更改,请参阅“参考实现”)

2. 只更改 PEP 484 (类型提示) 以接受 type1 | type2 语法?

PEP 563 (注解的延迟评估) 足以接受此提案,如果我们接受与注解的动态评估 (eval()) 不兼容。

>>> from __future__ import annotations
>>> def foo() -> int | str: pass
...
>>> eval(foo.__annotations__['return'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'type' and 'type'

3. 扩展 isinstance()issubclass() 以接受 Union

isinstance(x, str | int) ==> "is x an instance of str or int"

优点

  • 如果允许,那么实例检查可以使用一种极其简洁的记法。

缺点

  • 必须将所有 typing 模块迁移到 builtin 中。

参考实现

必须实现一个新的内置 Union 类型来保存 t1 | t2 的返回值,并且它必须受到 isinstance()issubclass() 的支持。这种类型可以放在 types 模块中。types.Uniontyping.Union 之间必须提供互操作性。

一旦 Python 语言扩展,mypy [1] 和其他类型检查器需要更新以接受这种新语法。

参考资料


来源:https://github.com/python/peps/blob/main/peps/pep-0604.rst

最后修改:2024-02-16 17:06:07 GMT