Python 3.9中有什么新内容?

116 阅读4分钟

自从几个月前加入Ubuntu 21.04以来,最新的Python版本在用户中变得越来越普遍。这让开发者有足够的理由立即在他们的项目中开始使用它。所以我们认为让你知道最新版本提供了哪些功能是公平的--你肯定会喜欢这些功能的

新的字符串方法str.removeprefixstr.removesuffix

这将是一个粉丝最喜欢的特性,因为它解决了Python旧的str 方法中一个相当混乱的混杂问题。

假设你想从一个文件名中删除.py 的扩展名,你怎么做?你会认为你当然可以使用str.rstrip 函数将扩展名从字符串的右端剥离出来,而且你是对的。

>>> file_string = 'my_test_file.py'
>>> file_name = file_string.rstrip('.py')
>>> file_name
'my_test_file'

...但这有一个致命的问题。看看你能不能从这个输出中找到问题所在。

>>> file_string = 'make_happy.py'
>>> file_name = file_string.rstrip('.py')
>>> file_name
'make_ha'

🤨为什么它删除了文件名的一部分?

嗯,这是因为rstrip (以及lstripstrip )并不接受一个 "字符串",而是接受一组要剥离的字符。因此,file_string.rstrip('.py') 并不意味着剥离.py ,而是意味着剥离这些字符中的任何一个。.,p, 和y, 这就是为什么我们文件名末尾的ppy 也要被剥离。而这恰恰在许多其他Pythonistas中引起了错误和混乱。

这就是为什么Python 3.9增加了两个新的方法:str.removeprefixstr.removesuffix ,它们确实把给定的字符串当作一个字符串。

>>> file_string = 'make_happy.py'
>>> file_name = file_string.removesuffix('.py')
>>> file_name
'make_happy'

新的dict 合并和更新语法

Python字典已经可以被合并和更新了,像这样:

>>> alice = {'apples': 1, 'bananas': 2}
>>> bob = {'carrots': 3}
>>> merged = {**alice, **bob}  # Dictionary unpacking added in Python 3.5
>>> merged
{'apples': 1, 'bananas': 2, 'carrots': 3}
>>> alice
{'apples': 1, 'bananas': 2}
>>> alice.update(bob)          # Updates alice in-place with bob's values
>>> alice
{'apples': 1, 'bananas': 2, 'carrots': 3}

由于合并和更新是字典非常常用的功能(就像集合一样),这个新增加的功能只是让这些操作变得更简单,用| 操作符。

>>> alice = {'apples': 1, 'bananas': 2}
>>> bob = {'carrots': 3}
>>> merged = alice | bob    # Merges the two into a new dictionary
>>> merged
{'apples': 1, 'bananas': 2, 'carrots': 3}
>>> alice
{'apples': 1, 'bananas': 2}
>>> alice |= bob            # Updates alice in-place
>>> alice
{'apples': 1, 'bananas': 2, 'carrots': 3}
>>>

标准集合中的类型提示泛型

我个人是这个新增功能的超级粉丝--如果你使用类型注释,你也会是这个的粉丝。从 Python 3.9 开始,你可以开始使用所有内置的集合类型。list,dict,set,collections.deque 等等。在你的类型注释中,而不是typing.List,typing.Deque 等等。不再需要typing 的导入!

# Previously:
from collections import defaultdict
from typing import DefaultDict, List, Set

values: List[int] = []
words: Set[str] = set()
counts: DefaultDict[int, int] = defaultdict(int)
# Starting from Python 3.9:
from collections import defaultdict

values: list[int] = []
words: set[str] = set()
counts: defaultdict[int, int] = defaultdict(int)

更多的信息可以在 PEP 585 中找到。

两个新模块

Python 3.9 引入了两个新模块。

  • zoneinfo 带来了对标准库中 IANA 时区数据库的支持。这意味着,Python 现在对诸如夏令时、一年中各国的时差等事情有了内置的支持。
  • graphlib它有一个拓扑排序算法的实现。所以你现在有一个内置的方法来解决复杂的图问题,比如在构建系统中对依赖关系进行排序。

CPython有一个新的、更强大的解析器

CPython现在使用了一个基于PEG 的新解析器,而不是以前的基于LL1 算法的解析器。这意味着,在Python中可以添加什么样的语法有一定的限制,因为老的解析器根本无法读取更复杂的代码。

这方面的一个例子是一个多行的with 语句。

# Previously:
with open('file1.txt') as f1, \
        open('file2.txt') as f2:
    print(f1.read())
    print(f2.read())

通常情况下,你会在多行语句周围使用小括号,以便有一个更可读的行分组,并避免在行尾放上尾数\-es。

但是Python 3.8中的旧解析器不支持这种语法。

# Starting from Python 3.9:
with (
    open('file1.txt') as f1,
    open('file2.txt') as f2,
):
    print(f1.read())
    print(f2.read())

新的和改进的PEG 解析器算法将能够处理更复杂的语法解析,如果将来需要的话。

更多信息可以在PEP 617中找到。

其他新增内容

  • CPython采用年度发布周期,即每年都会发布一个新的CPython小版本。
  • 新的random.Random.randbytes 方法来生成随机字节。
  • __file__ 内置变量现在总是一个绝对路径。
  • sys.stderr 从Python 3.9开始,"L "总是行缓冲的。
  • ast 模块更新:
    • 新增ast.unparse 方法,将 AST 转换为代码。
    • ast.dump() 增加了indent 选项,用于缩进,类似于json.dumps
  • PEP 614,放宽了对装饰器的语法限制。

总结

这个版本的 Python 给我们带来了许多方便的附加功能,同时也为下一步更大的功能奠定了基础,包括对分析器系统的更新和类型的改变。 要想更详细地了解这个版本的变化,你可以查看文档