Python 3.8中的新内容是什么?

168 阅读5分钟

最新的、最伟大的Python版本很快就会在测试版中推出。虽然离最终的稳定版还有一段时间,但值得关注所有的新内容。Python 3.8 为语言增加了一些新的语法,对现有的行为做了一些小的修改,主要是一些速度上的改进--保持了早期3.7版本的传统。

这篇文章概述了你应该知道的关于Python 3.8的最重要的新增内容和变化。请看一看

1.海象操作符

赋值表达式随着 "海象 "运算符:= ,来到了Python。这将使你能够把数值作为表达式的一部分分配给一个变量。这样做的主要好处是,当你想使用,比如说,一个表达式的值在随后的条件中使用时,它可以节省一些代码行。

所以,像这样的事情。{{< highlight python >}} line = f.readline() while line: ...# 处理行 line = f.readline() {{< /highlight>}}。

现在可以用简短的方式写成这样。{{< highlight python "hl_lines=1">}} while line := f.readline():...# 处理行 {{< /highlight>}}。

赞成简洁,但有人会说这影响了代码的可读性--可以说这里的第一种变体更清晰明确。这个讨论是Python社区中一个重大争议的中心。

2.仅有位置的参数

在定义一个方法的参数时,现在可以使用一个特殊的标记,/ ,以指定该函数只接受标记左边的位置性参数。在Python中,只有关键字的参数可以通过函数中的* 标记来实现,而为只有位置的参数增加/ 标记可以提高语言的一致性,并允许设计一个健壮的API。

以这个函数为例。{{< highlight python >}} def pow(x, y, z=None, /): r = x ** y if z is not None: r %= z return r {{< /highlight >}}.

这里的/ 标记意味着传递x,yz 的值只能在位置上进行,而不能使用关键字参数。其行为说明如下。

{{< highlight python >}}

pow(2, 10) # 有效 pow(2, 10, 17) # 有效 pow(x=2, y=10) # 无效,将引发TypeError pow(2, 10, z=17) # 无效,将引发TypeError {{< /highlight >}}。

关于动机和用例的更详细解释可以在PEP 570中找到。了解更多关于Python中仅有位置的参数

3. f-字符串现在支持"="

Python 程序员经常使用 "printf-style" 调试。在过去,这是很冗长的。

print "foo=", foo, "bar=", bar

f-strings 使其变得更漂亮。

print(f"foo={foo} bar={bar}")

但是你仍然不得不重复自己:你必须写出字符串"foo",然后再写出表达式"foo"。

= 指定器,作为f'{expr=}' ,扩展为表达式的文本,一个等号,然后是被评估的表达式的repr。所以现在,你可以简单地写。

这对语言来说是一小步,但对每个为调试而洒上print() 语句的人来说是一个巨大的飞跃!

4.reversed() 现在可以与dict

从 Python 3.7 开始,字典保留了键的插入顺序。reversed() 内置函数现在可以用来以相反的插入顺序访问字典--就像OrderedDict

>>> my_dict = dict(a=1, b=2)
>>> list(reversed(my_dict))
['b', 'a']
>>> list(reversed(my_dict.items()))
[('b', 2), ('a', 1)]

5.简化了returnyield的迭代解包

这种无意的行为从 Python 3.2 开始就存在了,它不允许在returnyield 语句中不加圆括号地解包迭代变量。

所以,下面的做法是允许的。

def foo():
    rest = (4, 5, 6)
    t = 1, 2, 3, *rest
    return t

但这些导致了SyntaxError : {{< highlight python "hl_lines=3">}} def baz(): rest = (4, 5, 6) return 1, 2, 3, *rest {{< /highlight >}}.

{{< highlight python "hl_lines=3">}} def baz(): rest = (4, 5, 6) yield 1, 2, 3, *rest {{< /highlight >}}.最新的版本修复了这一行为,所以做以上两种方法现在是允许的。

6.新的语法警告

Python 解释器现在在某些情况下会抛出一个SyntaxWarning ,即在 tuple 或 list 前漏掉一个逗号。所以当你不小心这样做时。

将显示一个有用的警告,而不是显示TypeError: 'tuple' object is not callable ,因为它并没有真正告诉你出了什么问题,而是指出你可能错过了一个逗号。在调试时很有帮助!

现在,当身份检查(isis not )与某些类型的字面符号(如字符串、整数等)一起使用时,编译器也会产生一个SyntaxWarning 。你很少想和除None 以外的字面符号比较身份,编译器的警告可以帮助避免一些难以捉摸的错误。

7.性能改进

这个版本为解释器增加了一些性能上的提升,与之前的3.7版本相一致:

  • operator.itemgetter() 现在快了33%。这是通过优化参数处理和为单个非负整数索引进入元组的常见情况(这是标准库中的典型使用情况)添加快速路径而实现的。

  • collections.namedtuple() 中的字段查找现在快了 2 倍多,使其成为 Python 中实例变量查找的最快形式。

  • 如果输入的迭代器有一个已知的长度 (输入实现了 len),list 构造函数不会过度分配内部项目缓冲区。这使得创建的列表平均小 12%。

  • 类变量的写入现在快了一倍:当一个非冗余属性被更新时,有一个不必要的对更新槽的调用,这被优化。

  • 一些简单的内建程序和方法的调用现在快了20-50%。向这些方法转换参数的开销被减少了。

  • uuid.UUID 现在使用slots来减少它的内存占用。

总结

即将发布的Python为该语言增加了一些伟大的新特性,并通过基本的加速修复显著提高了性能。在升级到Python 3.8时,有少量的行为变化可能需要修改现有的代码,但性能的提高和新的语法使其完全值得付出。所有新内容的详细变化日志可以在这里找到。