Python 3.14 的 3 个语法更新将使您的代码更安全、更好用
如 PEP 745 所述,Python 3.14 计划于 2025 年 10 月 7 日发布最终版本,其中包含令人兴奋的更新和增强功能。
它通过引入实验性的新解释器、优化各种内置模块和改进文件 I/O 操作,大大提高了性能。
因此,只需升级到 3.14 版,Python 程序就能运行得更快,而无需对现有代码进行任何修改。
由于大多数 Python 开发人员主要专注于构建应用程序,因此没有必要了解这些性能增强的每一个底层细节。
不过,Python 3.14 引入了三个语法变化,它们将影响我们编写 Python 程序的方式。
在本文中,我将探讨并清楚地解释这些变化,以帮助您在不断发展的 Python 生态系统中保持与时俱进。
1. 禁止在 finally
块中使用控制流语句
初级 Python 开发人员可能会犯一个常见错误–在 finally
块中编写控制流语句,包括 return
、break
或 continue
!
为什么会有问题呢?
因为 finally
块中的控制流语句总是会执行,所以它们会覆盖相应 try/except
块中的任何控制流,并可能导致意想不到的行为。
例如,下面的程序会打印出什么?
def return_example():
try:
print("In try block")
return "Try block return"
except Exception as e:
print(f"Exception: {e}")
finally:
print("In finally block")
return "Finally block return"
result = return_example()
print(f"Result: {result}")
是的,try
代码块内的 return
语句是无用的,result
变量将被 finally
代码块的返回值覆盖:
In try block
In finally block
Result: Finally block return
如果在 finally
块内有 continue
或 break
语句,也会出现类似问题:
def break_example():
for i in range(5):
try:
print(f"In try block, i = {i}")
if i == 3:
break # Should exit loop at i=2
except Exception as e:
print(f"Exception: {e}")
finally:
print("In finally block")
break
break_example()
# In try block, i = 0
# In finally block
正如上面的代码所示,由于 finally
块总是执行,当 i == 0
时,函数立即结束了循环。
危险在于,即使你编写了与示例类似的程序,Python 也不会发出任何警告。这可能是出现意外错误的根源。
幸运的是,Python 3.14 将为此做出重大改变。
正如 PEP 765 所规定的,当 return
、break
或 continue
语句出现在 finally
代码块中时,Python 3.14 将发出SyntaxWarning
。
这看起来很微妙,但可以节省我们大量的调试时间。
finally
块仅用于清理操作;不要在其中放置控制流语句。
2. 无括号异常处理
正确的异常处理对于代码的健壮性至关重要。
目前,如果我们需要捕获多个异常,就需要使用括号:
def divide(a, b):
try:
result = a / b
return result
except (ZeroDivisionError, TypeError):
print(f"Wrong input: {a} and {b}")
raise
为了更简洁,Python 3.14 将取消捕获多个异常时对括号的要求。因此,我们可以将上面的示例重写如下:
def divide(a, b):
try:
result = a / b
return result
except ZeroDivisionError, TypeError:
print(f"Wrong input: {a} and {b}")
raise
不过,这一点比较棘手,因为在使用 as
子句捕获异常实例时,仍然必须使用括号:
def divide(a, b):
try:
result = a / b
return result
except (ZeroDivisionError, TypeError) as e:
print(f"Error: {e}")
raise e
为什么需要?
正如 PEP 758 中解释的那样,不需要括号可能会造成混乱,因为不清楚到底是什么被分配给了目标。
就我个人而言,我对这一更新的印象并不深刻,但知道这一点还是很好的。如果有一天您在代码审查时看到了这段不需要括号的代码,请不要这么快就与您的同事争论。先看看是不是 Python 3.14。😄
3. 类型注解的延迟评估
Python 的类型提示有一个长期存在的烦恼。
例如,下面的代码会引发 NameError
:
class Node:
def __init__(self, value: int, next: Node):
self.value = value
self.next = next
# NameError: name 'Node' is not defined.
原因是 Python 在读取这段代码时,还没有完成对 Node
类的定义,就试图在类型提示中使用它。
简单地说,如果我们有一个类在注解中引用了它自己或另一个尚未定义的类,就会引发 NameError
。
有两种方法可以解决这个问题,但都不够优雅。
方法 1:使用字符串文字(引用未定义的注解):
class Node:
def __init__(self, value: int, next: 'Node'):
self.value = value
self.next = next
一种方法是引用未定义类型 Node
。当一个大型程序既有引号类型提示,又有未引号(正常)类型提示时,这可能会显得很混乱。但无论如何,它可以解决这个问题。
方法 2:使用 from __future__ import
annotations
Python 社区曾经尝试解决这个问题。从 Python 3.7 开始,我们可以导入一个 “神奇 “的模块 annotations
来使 NameError
消失:
from __future__ import annotations
class Node:
def __init__(self, value: int, next: Node):
self.value = value
self.next = next
这种特殊的导入方式使 Python 在运行时将所有注释都视为字符串字面量,这就是它能够工作的原因。这实际上是当前 Python 编程的首选方式。
然而,我们为什么要导入它呢?如果开发人员不知道这一点,就会对这个 “神奇 “模块的用法感到困惑。
幸运的是,Python 3.14 将使我们的生活变得更轻松。
在 Python 3.14 中,函数、类和模块注解不再在定义时执行。
取而代之的是,它们被存储在一种特殊的延迟形式中,只有在需要时才被求值。这意味着编写 def f(x: MyType) -> OtherType: ...
时不再在导入时对 MyType
和 OtherType
进行评估,而是将评估推迟到实际执行运行时反省时进行。(正如 PEP 649 和 PEP 749 所规定的那样。)
这一修改提高了 Python 代码的可读性和优雅性。
这意味着不需要用引号包装正向引用,也不需要使用 from __future__ import
注释作为变通方法。我们可以放心地在注解中使用未定义的类名,因为 Python 3.14 会处理它。
结论
在即将到来的 Python 3.14 中,在 finally
代码块中隐藏错误将受到警告,在异常处理中可以避免使用某些括号,类型提示更便宜、更易用。
这些并不是革命性的语法变化,但它引入的更新是经过深思熟虑的改进,使 Python 代码更安全、更简洁、更直观。
你也许感兴趣的:
- 14 个 Python 高级功能
- Python 的新 t-strings
- Python 异步编程的 9 个级别
- 您不应该再使用的 11 个过时 Python 模块
- Python 中 help() 函数的各种特性
- Python 奇特的自引用
- 揭秘 Python 的 10 个隐藏技巧
- 如果您使用 Python… 你现在就需要了解这 3 个工具!
- 【外评】Python 为何如此糟糕…
- 【外评】用 Python 解释 Rust 背后的思想或理念
你对本文的反应是: