看看Python 官网的文档 whatsnew,Python 3.10 已然距离我们越来越近了,然我们看看 Python 3.10 相较于 Python 3.9 有哪些改变吧
**的福音,以前在面对有多个上下文管理器时,我们只能采取多层嵌套的方式,像这样:
with open("read.txt", "r") as rfile: with open("write.txt", "w") as wfile: wfile.write(rfile.read())
会不会变成这样,[捂脸][捂脸][捂脸]
那在 Python3.10 中,我们可以这样写了:
with ( open("read.txt", "r") as rfile, open("write.txt", "w") as wfile ): wfile.write(rfile.read())
未闭合括号或引号
造成的语法错误,解释器可以提供具体出错的开头位置比如下面这段错误代码(是因为大括号没有闭合):
# filename: syntax_error_1.py expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, 38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6, some_other_code = foo()
Python 3.9 版本运行的报错信息,很难定位到错误原因:
> C:\Users\zioyi\.pyenv\pyenv-win\versions\3.9.6\python.exe syntax_error_1.py File "C:\Users\zioyi\python_code\syntax_error_1.py", line 3 some_other_code = foo() ^ SyntaxError: invalid syntax
再来看看 Python 3.10 的报错信息,就显得贴心很多了:
> C:\Users\zioyi\.pyenv\pyenv-win\versions\3.10.0b4\python.exe syntax_error_1.py File "C:\Users\zioyi\python_code\syntax_error_1.py", line 1 expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4, ^ SyntaxError: '{' was never closed
高亮
显示构成语法错误代码的完整错误范围先看一下 Python 3.9:
>>> foo(x, z for z in range(10), t, w) File "<stdin>", line 1 foo(x, z for z in range(10), t, w) ^ SyntaxError: Generator expression must be parenthesized
再看一下 Python 3.10:
>>> foo(x, z for z in range(10), t, w) File "<stdin>", line 1 foo(x, z for z in range(10), t, w) ^^^^^^^^^^^^^^^^^^^^ SyntaxError: Generator expression must be parenthesized
原来,^^^^^^^^^^^
这就是高亮
3. 错误信息变得更加智能
,不再只是无情的才裁判,只会返回SyntaxError: invalid syntax
,更像是一位循循善诱的老师
来看看当我们写错时,老师
(Pyhton 3.10) 是怎么引导我们的
>>> # 条件语句忘记加冒号 >>> if rocket.position > event_horizon File "<stdin>", line 1 if rocket.position > event_horizon ^ SyntaxError: expected ':' >>> # 解包元组时没写括号 >>> {x,y for x,y in zip('abcd', '1234')} File "<stdin>", line 1 {x,y for x,y in zip('abcd', '1234')} ^ SyntaxError: did you forget parentheses around the comprehension target? >>> # 构造字典时,两个元素之间没加逗号 >>> items = { ... x: 1, ... y: 2 ... z: 3, File "<stdin>", line 3 y: 2 ^ SyntaxError: invalid syntax. Perhaps you forgot a comma? >>> # 准备补货多个异常,却少写了括号 >>> try: ... build_dyson_sphere() ... except NotEnoughScienceError, NotEnoughResourcesError: File "<stdin>", line 3 except NotEnoughScienceError, NotEnoughResourcesError: ^ SyntaxError: multiple exception types must be parenthesized
现在缩进错误
会有更多关于期望缩进的块类型的上下文信息,包括语句的位置:
>>> def foo(): ... if lel: ... x = 2 File "<stdin>", line 3 x = 2 ^ IndentationError: expected an indented block after 'if' statement in line 2
当出现熟悉错误
时,PyErr_Display
函数会猜你喜欢,打印出你可能要的属性:
>>> collections.namedtoplo Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'collections' has no attribute 'namedtoplo'. Did you mean: namedtuple?
和属性错误一样,当出现命名错误
时,PyErr_Display
函数会猜你喜欢,打印出你可能要的变量名:
>>> schwarzschild_black_hole = None >>> schwarschild_black_hole Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'schwarschild_black_hole' is not defined. Did you mean: schwarzschild_black_hole?
PyErr_Display
真是一个懂事的函数
别人(Java、Golang、C)有的,你(Pyhton)也会有的,而且只会更好!
响应全网呼声,Python 版switch-case
,即match-case
也终于来了,这个特性也是 Python 3.10 中最受瞩目的特性
Python 版的switch-case
,你要按照这个格式去写:
match subject: case <pattern_1>: <action_1> case <pattern_2>: <action_2> case <pattern_3>: <action_3> case _: <action_wildcard>
在没有match-case
之前,我们是这样写的:
def http_error_if_else(status): if status == 400: return "Bad request" elif status == 404: return "Not found" elif status == 418: return "I'm a teapot" else: return "Something's wrong with the internet" # 或者这样 def http_error_dict(status): http_status_to_error = { 400: "Bad request", 404: "Not found", 418: "I'm a teapot" } return http_status_to_error.get(status, "Something's wrong with the internet")
虽然可以解决问题,但我们知道if-else
在性能上和易读性上都没有switch-case
好用
再看看 Python 3.10 里,我们就可以这样写了:
def http_error_match_case(status): match status: case 400: return "Bad request" case 404: return "Not found" case 418: return "I'm a teapot" case _: return "Something's wrong with the internet"
这就变得简单了许多
你还可以在case
后面用使用|
来串联多个,像这样:
case 401 | 403 | 404: return "Not allowed"
如果不在case
语句中使用_
兜底,则可能不存在匹配项。如果不存在匹配项,则行为为空操作。例如,如果状态500
被传递,则会发生空操作。
在进行匹配时,会按照case
后的pattern
对subject
尝试进行转换,来绑定pattern
中的变量,.在这个例子中,一个数据点可以解包到它的 x 坐标和 y 坐标:
# point is an (x, y) tuple match point: case (0, 0): print("Origin") case (0, y): print(f"Y={y}") case (x, 0): print(f"X={x}") case (x, y): print(f"X={x}, Y={y}") case _: raise ValueError("Not a point")