举例说明如何用pyupgrade升级语法?

386 阅读2分钟

最近的几个PEP使得编写类型提示变得更加容易。

  • PEP 585为内置类型添加了通用语法,这使得我们可以编写例如list[int] ,而不是使用typing.List[int]

  • PEP 604| 操作符添加为联合语法,这使得我们可以写例如int | str ,而不是typing.Union[int, str] ,以及int | None ,而不是typing.Optional[int]

PEP 585在Python 3.9中发布,PEP 604将在Python 3.10中发布,目前正在测试中。 但是我们今天可以使用这两种语法,甚至从Python 3.7开始,用Mypy 0.800+和推迟评估的 from __future__ import annotations

例如,以这段使用语法的代码为例。

from typing import Dict, List, Optional, Union

x: Dict[str, int] = {"a": 1}

y: Union[int, float] = 2.2

z: List[Optional[int]] = [1, None, 3]

我们可以像这样重写它。

from __future__ import annotations

# PEP 585 builtin generics
x: dict[str, int] = {"a": 1}

# PEP 604 union operator
y: int | float = 2.2

# Combining them
z: list[int | None] = [1, None, 3]

但我们所有的旧代码怎么办? 我们现在是不是要用两种方式来做事情,直到我们做大量的手工重写?

不!不!不

感谢pyupgrade 工具,我们可以自动升级我们的语法。pyupgrade 知道如何将许多形式的旧Python语法改写成新的等价物。

我们可以用一个标志来指定我们的目标Python版本,例如:--py39-plus 用于Python 3.9。pyupgrade 将为适当的目标Python版本激活它的PEP 585和604类型提示重写,或者为使用from __future__ import annotations 的文件。

例如,我们可以这样执行上述重写。

$ python -m pip install pyupgrade
Collecting pyupgrade
  Downloading pyupgrade-2.18.1-py2.py3-none-any.whl (50 kB)
     |████████████████████████████████| 50 kB 1.4 MB/s
Collecting tokenize-rt>=3.2.0
  Using cached tokenize_rt-4.1.0-py2.py3-none-any.whl (6.1 kB)
Installing collected packages: tokenize-rt, pyupgrade
Successfully installed pyupgrade-2.18.1 tokenize-rt-4.1.0
$ pyupgrade example.py
Rewriting example.py

这就重写了语法,但保留了导入的内容。

from __future__ import annotations

from typing import Dict, List, Optional, Union

x: dict[str, int] = {"a": 1}

y: int | float = 2.2

z: list[int | None] = [1, None, 3]

很好!现在我们要处理的是旧的typing 导入,它现在没有被使用。我们可以手动删除它们,但是还有一个*工具可以帮助我们:Timothy Crosley 的isort。isort 的--rm 标志允许我们从目标文件中放弃导入。

(*还有一个工具,reorder_python_imports ,也是由Anthony Sottile开发的。它有一个类似的--remove-import 标志。我只是习惯于isort。)

在这种情况下,我们要像这样运行它。

$ python -m pip install isort
Collecting isort
  Using cached isort-5.8.0-py3-none-any.whl (103 kB)
Installing collected packages: isort
Successfully installed isort-5.8.0
$ isort --rm 'from typing import Dict' --rm 'from typing import List' --rm 'from typing import Optional' --rm 'from typing import Union' example.py
Fixing /Users/chainz/tmp/hints/example.py

现在我们的代码已经干净地升级到了闪亮的新语法。

from __future__ import annotations

x: dict[str, int] = {"a": 1}

y: int | float = 2.2

z: list[int | None] = [1, None, 3]