还记得2016年吗?当全世界都在忙于 Pokemon Go 和里约奥运会时,我还是一名睁大眼睛的大学生,正在写下我的第一个“Hello, World!”。在Python中。当时,我不知道字典顺序保留意味着什么,更不用说为什么 Python 社区热议将其包含在即将发布的 3.6 版本中。现在,作为一名经验丰富的开发人员回顾过去,我和 Python 已经取得了如此大的进步,真是令人惊叹。
从 3.6 中的 f 字符串到 3.10 中改变游戏规则的模式匹配,再到现在 3.13 中的自由线程功能,Python 不断突破我们可以使用更简洁、更具表现力的代码实现的界限。这就像看着你最喜欢的超级英雄在每部电影中获得新的力量 - 除了不是射网或挥舞锤子,我们正在获得更好的工具来对抗真正的恶棍:代码复杂性和冗长。
在本文中,我们将启动时间机器,浏览从 3.6 到 3.13 的每个 Python 版本中引入的最重要的功能。我们将了解每个版本的主要功能,探索它们如何改变我们编写 Python 代码的方式。无论您是一位想要回忆过去的经验丰富的 Python 爱好者,还是对这门语言的演变感到好奇的新手,请系好安全带——我们将踏上一段令人兴奋的 Python 历史之旅!
在本次旅程结束时,您可能会发现自己看着旧代码并思考,“哇,没有这些功能我们如何生活?”让我们深入了解一下我们最喜欢的功能如何多年来,蛇不断蜕皮,每次蜕变都变得更加强大。
如果有一个功能让 Python 开发人员集体松了一口气,那就是 f 字符串。还记得 .format() 和 % 格式化的日子吗? F 字符串突然出现,将我们从冗长的字符串格式化噩梦中解救出来。
# The old ways name, language, year = "Alice", "Python", 2016 print("{} started learning {} in {}".format(name, language, year)) # .format() print("%s started learning %s in %d" % (name, language, year)) # % formatting # The f-string way print(f"{name} started learning {language} in {year}") # But wait, there's more! F-strings can handle expressions items = ["code", "coffee", "bugs"] print(f"Developer life: {', '.join(items[:-1])} and {items[-1]}") print(f"Hours coding today: {8 * 2}") # Math? No problem! # They even work with method calls message = " python rocks " print(f"Confession: {message.strip().title()}")
对于我们这些处理大量数据的人来说,这个功能改变了游戏规则。不再需要在屏幕上数零!
# The old ways name, language, year = "Alice", "Python", 2016 print("{} started learning {} in {}".format(name, language, year)) # .format() print("%s started learning %s in %d" % (name, language, year)) # % formatting # The f-string way print(f"{name} started learning {language} in {year}") # But wait, there's more! F-strings can handle expressions items = ["code", "coffee", "bugs"] print(f"Developer life: {', '.join(items[:-1])} and {items[-1]}") print(f"Hours coding today: {8 * 2}") # Math? No problem! # They even work with method calls message = " python rocks " print(f"Confession: {message.strip().title()}")
类型提示以前就存在,但 Python 3.6 通过变量注释使它们更加灵活。它允许更清晰的类型提示,为更好的静态分析铺平道路。
# Before: Is this a billion or a million? ? old_budget = 1000000000 # After: Crystal clear! ? new_budget = 1_000_000_000 # Works with different number types hex_address = 0xFF_FF_FF_FF # Much easier to read! binary_flag = 0b_1111_0000 # Grouping bits
额外提示:这些注释不会影响运行时行为 - 它们是对开发人员和工具的提示。但它们使您的 IDE 的自动完成功能像魔术一样工作! ✨
还记得用一堆 __init__ 参数编写类,然后煞费苦心地分配每个参数吗?数据类通过自动生成样板代码(如 __init__、__repr__ 和 __eq__)简化了类的创建。
# Before Python 3.6 (still works, but less flexible) def get_user_data(user_id: int) -> dict: pass # Python 3.6 style from typing import Dict, List, Optional # Class attributes with type hints class UserDataAnalyzer: premium_users: List[int] = [] cache: Dict[int, str] = {} last_analyzed: Optional[str] = None def analyze_user(self, user_id: int) -> None: # Some analysis logic here self.last_analyzed = "2024-10-07"
这个功能听起来很无聊,但却解决了一个令人头疼的问题:启用前向引用并通过惰性评估提高性能。
from dataclasses import dataclass from datetime import datetime # Before dataclasses ? class OldBooking: def __init__(self, id, destination, traveler, date, price): self.id = id self.destination = destination self.traveler = traveler self.date = date self.price = price def __repr__(self): return f"Booking({self.id}, {self.destination}, {self.traveler})" def __eq__(self, other): return isinstance(other, OldBooking) and self.id == other.id # After dataclasses ? @dataclass class Booking: id: int destination: str traveler: str date: datetime price: float def total_with_tax(self, tax_rate: float = 0.1) -> float: return self.price * (1 + tax_rate) # Using our dataclass trip = Booking( id=42, destination="Python Island", traveler="Pythonista", date=datetime.now(), price=199.99 ) print(f"Trip cost with tax: ${trip.total_with_tax():.2f}")
输入 import pdb 的日子已经一去不复返了; pdb.set_trace()。现在我们可以放下断点()并继续我们的生活!
from __future__ import annotations from typing import List class ChessGame: def __init__(self): self.players: List[Player] = [] # This now works! self.board: Board = Board() # This too! def add_player(self, player: Player) -> None: self.players.append(player) def get_winner(self) -> Player | None: # Python 3.10 union type just for fun! # Game logic here return None class Player: def __init__(self, name: str, rating: int): self.name = name self.rating = rating class Board: def __init__(self): self.moves: List[tuple[Player, str]] = []
调试提示:设置 PYTHONBREAKPOINT 环境变量来控制断点行为:
def calculate_universe_answer(): numbers = list(range(43)) breakpoint() # Your IDE probably supports this better than pdb! return sum(numbers) - 903 def main(): print("Calculating the answer to life, universe, and everything...") result = calculate_universe_answer() print(f"The answer is: {result}") # When you run this, you'll drop into a debugger at the breakpoint # Try these in the debugger: # - 'numbers' to see the list # - 'len(numbers)' to check its length # - 'n' to go to next line # - 'c' to continue execution
Python 3.7 可能不像 3.6 那样华丽,但它带来了一些严重的生活质量改进。仅数据类就可能在全球范围内节省数百万次击键!任何能让调试变得更容易的东西在镀金蟒蛇中都是值得的。
Python 中最具争议但最强大的补充。它允许您将值分配给变量作为较大表达式的一部分。
海象运算符允许您同时做两件事:
# Disable all breakpoints export PYTHONBREAKPOINT=0 # Use a different debugger (like IPython's) export PYTHONBREAKPOINT=IPython.embed
当你想说“这些参数放在这里,没有问题!”。您可以指定必须按位置而不是关键字传递的参数。此功能增强了 API 设计灵活性,并可以防止函数签名发生重大更改。
# Consider this code example: while True: user_input = input("Enter something (or 'quit' to exit): ") if user_input == 'quit': break print(f"You entered: {user_input}") # We can simplify above code using walrus operator like this: while (user_input := input("Enter something (or 'quit' to exit): ")) != 'quit': print(f"You entered: {user_input}")
在 f 字符串中添加了对 = 的支持,使调试更容易。
def create_character(name, /, health=100, *, special_move): return f"{name}: {health}HP, Special: {special_move}" # These work player1 = create_character("Pythonista", special_move="Code Sprint") player2 = create_character("Bug Slayer", health=120, special_move="Debug Strike") # This fails - name must be positional # player3 = create_character(name="Syntax Error", special_move="Crash Game")
海象运算符让我们编写更简洁的代码(尽管能力越大,责任越大!),仅位置参数使我们能够更好地控制函数接口,而 f 字符串调试使打印调试变得非常愉快。
最后,Python 为我们提供了一种简洁的方式来合并字典!还记得我们必须编写 dict1.update(dict2) 或使用 {**dict1, **dict2} 的日子吗?那些日子现在已经过去了。
# The old ways name, language, year = "Alice", "Python", 2016 print("{} started learning {} in {}".format(name, language, year)) # .format() print("%s started learning %s in %d" % (name, language, year)) # % formatting # The f-string way print(f"{name} started learning {language} in {year}") # But wait, there's more! F-strings can handle expressions items = ["code", "coffee", "bugs"] print(f"Developer life: {', '.join(items[:-1])} and {items[-1]}") print(f"Hours coding today: {8 * 2}") # Math? No problem! # They even work with method calls message = " python rocks " print(f"Confession: {message.strip().title()}")
这个添加消除了对typing.List、typing.Dict等的需要,简化了类型注释。
# Before: Is this a billion or a million? ? old_budget = 1000000000 # After: Crystal clear! ? new_budget = 1_000_000_000 # Works with different number types hex_address = 0xFF_FF_FF_FF # Much easier to read! binary_flag = 0b_1111_0000 # Grouping bits
这些看起来很简单,但它们对于文本处理来说非常强大。不再需要使用硬编码长度进行笨重的字符串切片或 Replace() 调用!
# Before Python 3.6 (still works, but less flexible) def get_user_data(user_id: int) -> dict: pass # Python 3.6 style from typing import Dict, List, Optional # Class attributes with type hints class UserDataAnalyzer: premium_users: List[int] = [] cache: Dict[int, str] = {} last_analyzed: Optional[str] = None def analyze_user(self, user_id: int) -> None: # Some analysis logic here self.last_analyzed = "2024-10-07"
Python 3.10(2021 年 10 月发布)带来了一些非常棒的模式匹配功能。
开关盒是过去十年的事。模式匹配就像数据结构的瑞士军刀一样出现。这不仅仅是价值观的匹配;这是关于用代码侍酒师的优雅来解构数据。
from dataclasses import dataclass from datetime import datetime # Before dataclasses ? class OldBooking: def __init__(self, id, destination, traveler, date, price): self.id = id self.destination = destination self.traveler = traveler self.date = date self.price = price def __repr__(self): return f"Booking({self.id}, {self.destination}, {self.traveler})" def __eq__(self, other): return isinstance(other, OldBooking) and self.id == other.id # After dataclasses ? @dataclass class Booking: id: int destination: str traveler: str date: datetime price: float def total_with_tax(self, tax_rate: float = 0.1) -> float: return self.price * (1 + tax_rate) # Using our dataclass trip = Booking( id=42, destination="Python Island", traveler="Pythonista", date=datetime.now(), price=199.99 ) print(f"Trip cost with tax: ${trip.total_with_tax():.2f}")
Python 3.10 引入了一种使用括号处理多个上下文管理器的简洁方法。
from __future__ import annotations from typing import List class ChessGame: def __init__(self): self.players: List[Player] = [] # This now works! self.board: Board = Board() # This too! def add_player(self, player: Player) -> None: self.players.append(player) def get_winner(self) -> Player | None: # Python 3.10 union type just for fun! # Game logic here return None class Player: def __init__(self, name: str, rating: int): self.name = name self.rating = rating class Board: def __init__(self): self.moves: List[tuple[Player, str]] = []
Python 认为“AttributeError”不够有帮助,并选择了“您的意思是……”建议。这就像有一个内置的代码审查员,他实际上想要提供帮助,而不仅仅是指出你的错误。
def calculate_universe_answer(): numbers = list(range(43)) breakpoint() # Your IDE probably supports this better than pdb! return sum(numbers) - 903 def main(): print("Calculating the answer to life, universe, and everything...") result = calculate_universe_answer() print(f"The answer is: {result}") # When you run this, you'll drop into a debugger at the breakpoint # Try these in the debugger: # - 'numbers' to see the list # - 'len(numbers)' to check its length # - 'n' to go to next line # - 'c' to continue execution
有趣的事实:模式匹配语法受到 Rust 和其他函数式编程语言的启发,但 Python 使其更加 Pythonic。如果您来自 Scala 或 Elixir 等语言,您会感到宾至如归!
Python 3.11 带来了我们都渴望的东西——速度的大幅提升!这个版本不仅速度快,而且速度快。它“比 Python 3.10 快了 60%”,平均快了 25%。但这还不是它带来的全部。让我带您了解使该版本变得特别的最令人兴奋的功能。
虽然这不是您可以在代码中“看到”的功能,但您肯定会感觉到。 Python 3.11 引入了专门的自适应解释器,可以使您的代码运行速度显着加快。这是一个简单的示例来演示:
# Disable all breakpoints export PYTHONBREAKPOINT=0 # Use a different debugger (like IPython's) export PYTHONBREAKPOINT=IPython.embed
在 CPU 密集型任务、错误处理和深度嵌套函数调用中,速度提升尤其明显。这就像 Python 去了健身房并恢复了前所未有的缓冲! ?
在处理可能同时发生多个错误的并发操作时,此功能是一个救星。我们现在可以将多个异常作为一组处理,而不是只捕获一个异常!
# The old ways name, language, year = "Alice", "Python", 2016 print("{} started learning {} in {}".format(name, language, year)) # .format() print("%s started learning %s in %d" % (name, language, year)) # % formatting # The f-string way print(f"{name} started learning {language} in {year}") # But wait, there's more! F-strings can handle expressions items = ["code", "coffee", "bugs"] print(f"Developer life: {', '.join(items[:-1])} and {items[-1]}") print(f"Hours coding today: {8 * 2}") # Math? No problem! # They even work with method calls message = " python rocks " print(f"Confession: {message.strip().title()}")
Python 3.11 通过更精确地查明错误提高了开发人员的工作效率。就像有一个内置的调试助手!
# Before: Is this a billion or a million? ? old_budget = 1000000000 # After: Crystal clear! ? new_budget = 1_000_000_000 # Works with different number types hex_address = 0xFF_FF_FF_FF # Much easier to read! binary_flag = 0b_1111_0000 # Grouping bits
在处理复杂的数学运算或嵌套方法调用时,这些错误消息特别有用。不再需要手动计算括号!
Python 3.11 不仅仅是另一个增量更新,它是性能和开发人员体验方面的巨大飞跃。仅速度的改进就使其成为一项引人注目的升级,但加上新的异常处理功能和增强的错误消息,您就拥有了一个真正配得上“The Speedster”称号的版本!
使用 Python 3.12,f 字符串变得更好!早期版本有一些限制 - f 字符串内没有反斜杠或注释,复杂的表达式有时需要解决方法。
# Before Python 3.6 (still works, but less flexible) def get_user_data(user_id: int) -> dict: pass # Python 3.6 style from typing import Dict, List, Optional # Class attributes with type hints class UserDataAnalyzer: premium_users: List[int] = [] cache: Dict[int, str] = {} last_analyzed: Optional[str] = None def analyze_user(self, user_id: int) -> None: # Some analysis logic here self.last_analyzed = "2024-10-07"
您不再需要显式导入 TypeVar 或 Generic,从而在不牺牲功能的情况下减少样板文件并提高代码可读性。
from dataclasses import dataclass from datetime import datetime # Before dataclasses ? class OldBooking: def __init__(self, id, destination, traveler, date, price): self.id = id self.destination = destination self.traveler = traveler self.date = date self.price = price def __repr__(self): return f"Booking({self.id}, {self.destination}, {self.traveler})" def __eq__(self, other): return isinstance(other, OldBooking) and self.id == other.id # After dataclasses ? @dataclass class Booking: id: int destination: str traveler: str date: datetime price: float def total_with_tax(self, tax_rate: float = 0.1) -> float: return self.price * (1 + tax_rate) # Using our dataclass trip = Booking( id=42, destination="Python Island", traveler="Pythonista", date=datetime.now(), price=199.99 ) print(f"Trip cost with tax: ${trip.total_with_tax():.2f}")
Python 历史最悠久的痛点之一是全局解释器锁 (GIL),这是一种一次只允许一个线程执行 Python 字节码的机制。这导致了多线程程序的性能瓶颈,尤其是 CPU 密集型任务。然而,Python 3.12 引入了一项重大改进:Per-Interpreter GIL。
简单来说,GIL 阻止了 Python 真正同时执行多个线程。尽管线程通常用于 I/O 密集型操作(例如读取文件或发出网络请求),但 GIL 限制了多线程处理 CPU 密集型工作负载的优势。对于需要利用多核处理器的 Python 开发人员来说,这长期以来一直是一个挑战。
在Python 3.12中,解释器现在拥有自己的GIL,允许同一进程中的多个解释器并行运行,而不受单个全局锁的约束。这对于多核处理特别有用。 但是,Python 3.12 仅通过 C-API 支持每解释器 GIL。 Python 3.13 将添加完整的 Python-API 支持。
有关此功能的更多信息:
Python 3.12 可能不会像 3.11 那样立即产生性能影响,但它对类型系统人体工程学和 f 字符串功能的改进使其成为编写可维护、类型安全代码的重要版本。这些功能在代码清晰度和类型安全至关重要的大型项目中特别有价值。
Python 3.13 增强了 Read-Eval-Print-Loop (REPL),使其更智能、更用户友好。现在,REPL 可以更有效地执行多行代码,显示更好的语法建议,并提供改进的自动完成体验。
新的 REPL 具有以下新功能:
多年来,Python 开发人员一直陷入围绕全局解释器锁 (GIL) 的微妙舞蹈中,这是一种阻止多个本机线程同时执行 Python 字节码的机制。虽然 GIL 有其优点,但它也是多线程应用程序的瓶颈。
Python 3.13 中的自由线程模式旨在通过禁用 GIL 来打破这些链条。这使得多线程 Python 程序能够实现真正的并行性。从本质上讲,您的线程现在可以同时运行,从而充分利用多核处理器。在以前的版本中,GIL 会强制这些线程一次运行一个,从而有效地序列化执行。
您可以下载 macOS 或 Windows 的安装程序 - 它们有一个自由线程选项,或者您可以使用 pyenv 从源代码构建和安装(推荐):pyenv install 3.13.0t
注意:虽然自由线程模式是 Python 发展过程中的一个重大进步,但重要的是要记住它的实验状态(预计会出现一些错误)。此外,由于禁用了专用自适应解释器 (PEP 659),自由线程构建的单线程性能下降了 40%。
实验性的即时 (JIT) 编译器标志着 Python 发展过程中的另一个重要里程碑。 JIT 编译器的工作原理是在运行时动态地将 Python 字节码翻译为机器代码。它使用一种称为“复制和修补”的技术来完成此操作。这意味着频繁执行的代码路径是即时编译的,这理论上可以为代码的关键部分带来显着的性能改进。
现在,先别太兴奋。在目前的形式中,JIT 编译器并不是为了让你的代码更快——它只是为了跟上常规的 Python 性能。但它在执行此操作的同时向流程添加了额外的步骤,这令人印象深刻。 Python 团队对这个小引擎制定了宏伟的计划,希望在未来的版本中对其进行加速,以便在不占用内存的情况下为我们带来一些真正的速度提升。现在,更多的是证明这个概念,为未来的优化奠定基础。
当我们纪念 Python 3.13 的发布时,有一件事很明确:Python 的发展不仅仅是添加功能 - 它是为了让开发人员的生活更轻松,一次发布一个版本。这不仅仅是编写代码;这是关于编写更好、更优雅、更少麻烦的代码。
所以,各位 Python 爱好者,我们不要满足于现状。今天的Python不是我们昨天学的Python,明天的Python可能会再次给我们带来惊喜。不断探索,不断学习,不断突破这两个简单词的可能性界限:导入这个
本文最初发表于我的个人博客。
以上是Pythonic Time Capsule:每个版本必须了解的功能的详细内容。更多信息请关注PHP中文网其他相关文章!