在 Python 中的最新版本发布!自夏季以来,Python 3.8 已在 beta 版本中可用,但在 2019 年 10 月 14 日,第一个正式版本已准备就绪。现在,我们所有人都可以开始使用新功能并从最新改进中受益。
Python 3.8 带来了什么?该文档很好地概述了新功能。但是,本文将更深入地介绍一些最大的变化,并向您展示如何利用 Python 3.8。
在本文中,您将了解:
-
使用赋值表达式简化一些代码结构
-
在自己的函数中强制仅位置参数
-
指定更精确的类型提示
-
使用 f 字符串进行更简单的调试
除了少数例外,Python 3.8 对早期版本进行了许多小的改进。在本文结尾处,您将看到许多不那么引人注意的更改,并讨论了一些使 Python 3.8 比其先前版本更快的优化。最后,您将获得有关升级到新版本的一些建议。
房间里的海象:赋值表达
Python 3.8 中最大的变化是赋值表达式的引入。它们使用新的符号(:=
)编写。该运算符通常被称为海象运算符,因为它类似于海象的侧面的象牙和海象牙。
赋值表达式使您可以在同一表达式中赋值并返回一个值。例如,如果要分配给变量并打印其值,则通常需要执行以下操作:
>>> walrus = False
>>> print(walrus)
False
复制代码
在 Python 3.8 中,可以使用 walrus 运算符将这两个语句合并为一个:
>>> print(walrus := True)
True
复制代码
分配表达式使您可以分配True
给walrus
,并立即打印该值。但是请记住,如果没有它,海象运算符不会做任何不可能的事情。它只会使某些构造更加方便,并且有时可以更清楚地传达代码的意图。
一种显示海象运算符优势的模式是while
循环,您需要在循环中初始化和更新变量。例如,以下代码要求用户输入直到输入quit
:
inputs = list()
current = input("Write something: ")
while current != "quit":
inputs.append(current)
current = input("Write something: ")
复制代码
此代码不理想。您正在重复该input()
语句,并且需要以某种方式将其添加current
到列表中,然后再询问用户。更好的解决方案是设置一个无限while
循环,然后使用它break
来停止循环:
inputs = list()
while True:
current = input("Write something: ")
if current == "quit":
break
inputs.append(current)
复制代码
这会将测试移回应有的while
行。但是,该行现在发生了几件事,因此需要花费更多的精力才能正确地阅读它。对于海象运算符何时有助于使您的代码更具可读性,请做出最佳判断。
PEP 572 描述了赋值表达式的所有细节,包括将其引入语言的一些原理,以及如何使用海象运算符的几个示例。
仅位置参数
内置函数float()
可用于将文本字符串和数字转换为float
对象。考虑以下示例:
>>> float("3.8")
3.8
>>> help(float)
class float(object)
| float(x=0, /)
|
| Convert a string or number to a floating point number, if possible.
[...]
复制代码
仔细看看的签名float()
。注意/
参数后的斜杠()。这是什么意思?
注意:有关该/
符号的深入讨论,请参阅 PEP 457-仅位置参数的符号。
事实证明,虽然float()
调用了一个参数,x
但不允许使用其名称:
>>> float(x="3.8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float() takes no keyword arguments
复制代码
使用时float()
,只允许按位置而不是关键字指定参数。在 Python 3.8 之前,此类仅位置参数仅适用于内置函数。没有简单的方法来指定参数在您自己的函数中应该仅位置:
>>> def incr(x):
... return x + 1
...
>>> incr(3.8)
4.8
>>> incr(x=3.8)
4.8
复制代码
这是可能的模拟位置-only 参数使用*args
,但是这是不够灵活,不易阅读,并迫使你实现自己的参数解析。在 Python 3.8 中,您可以/
用来表示必须由位置指定之前的所有参数。您可以重写incr()
为仅接受位置参数:
>>> def incr(x, /):
... return x + 1
...
>>> incr(3.8)
4.8
>>> incr(x=3.8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: incr() got some positional-only arguments passed as
keyword arguments: 'x'
复制代码
通过/
在之后添加x
,您可以将其指定x
为仅位置参数。您可以将常规参数与仅位置参数结合使用,方法是将常规参数放在斜杠之后:
>>> def greet(name, /, greeting="Hello"):
... return f"{greeting}, {name}"
...
>>> greet("Łukasz")
'Hello, Łukasz'
>>> greet("Łukasz", greeting="Awesome job")
'Awesome job, Łukasz'
>>> greet(name="Łukasz", greeting="Awesome job")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: greet() got some positional-only arguments passed as
keyword arguments: 'name'
复制代码
在中greet()
,斜线放在name
和之间greeting
。这意味着它name
是仅位置参数,greeting
而是可以通过位置或关键字传递的常规参数。
乍一看,仅位置参数似乎有点局限性,与 Python 关于可读性重要性的口号背道而驰。您可能会发现在很多情况下仅位置参数可以改善您的代码。
但是,在正确的情况下,仅位置参数可以在设计函数时提供一定的灵活性。首先,当您的参数具有自然顺序但很难给其提供良好的描述性名称时,仅位置参数才有意义。
使用仅位置参数的另一个可能的好处是,您可以更轻松地重构函数。特别是,您可以更改参数的名称,而不必担心其他代码取决于这些名称。
仅位置参数很好地补充了仅关键字参数。在任何版本的 Python 3 中,都可以使用星号(*
)指定仅关键字的参数。任何参数后 *
,必须使用关键字来指定:
>>> def to_fahrenheit(*, celsius):
... return 32 + celsius * 9 / 5
...
>>> to_fahrenheit(40)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: to_fahrenheit() takes 0 positional arguments but 1 was given
>>> to_fahrenheit(celsius=40)
104.0
复制代码
celsius
是仅关键字的参数,因此,如果您尝试根据不含关键字的位置进行指定,Python 会引发错误。
您可以通过按/
和分隔此顺序的顺序来组合仅位置,常规和仅关键字的参数*
。在以下示例中,text
是仅位置参数,border
是具有默认值的常规参数,并且width
是具有默认值的仅关键字参数:
>>> def headline(text, /, border="♦", *, width=50):
... return f" {text} ".center(width, border)
...
复制代码
由于text
仅位置定位,因此您不能使用关键字text
:
>>> headline("Positional-only Arguments")
'♦♦♦♦♦♦♦♦♦♦♦ Positional-only Arguments ♦♦♦♦♦♦♦♦♦♦♦♦'
>>> headline(text="This doesn't work!")
Traceback (most recent call last):
File "<stdin>"