還記得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中文網其他相關文章!