Python 3.10 的發布日益臨近,是時候來看看它將帶來的最重要的新特性和變化了。內容包括類型檢查,類型別名,switch/case語法,數量統計,上下文管理器,性能等。
作者:Martin Heinz
編譯:McGL
每年的這個時候,最新的 Python alpha 版本陸續發布(昨天剛發布了 alpha 第七版),第一個 beta 版即將推出(預計下個月3號),所以現在正是試用 Python 新版本的理想時機,看看 Python 3.10中有哪些酷炫的新功能即將推出!
安裝 Alpha/Beta 版如果想嘗試最新和最好版本的 Python 的所有特性,你需要安裝 Alpha/Beta 版本。但是考慮到這個版本還不穩定,我們不希望用它覆蓋默認的 Python 安裝。所以要保留現有的解釋器同時安裝 Python 3.10,我們可以使用以下方法:
wget https://www.python.org/ftp/python/3.10.0/Python-3.10.0a7.tgz
tar xzvf Python-3.10.0a7.tgz
cd Python-3.10.0a7
./configure --prefix=$HOME/python-3.10.0a7
make
make install
$HOME/python-3.10.0a7/bin/python3.10
在運行上面的代碼之後,你會看到 Python 3.10 Alpha IDLE:
Python 3.10.0a7 (default, Apr 16 2021, 11:50:33) [GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
安裝了 Python 3.10 之後,我們來看看所有的新特性和變化.
類型檢查(Type Checking)改進如果你在 Python 中使用過類型檢查,會很高興看到 Python 3.10 將包括很多類型檢查改進,包括語法更清晰的 類型 Union 運算符:
# Function that accepts either `int` or `float`
# Old:
def func(value: Union[int, float]) -> Union[int, float]:
return value
# New:
def func(value: int | float) -> int | float:
return value
除此之外,這個簡單的改進不僅限於類型注釋,還可以用於isinstance() 和 issubclass() 函數:
isinstance("hello", int | str)
# True
在 Python 的早期版本中,增加了類型別名,以允許我們創建表示用戶定義類型的別名。在 Python 3.9 或更早的版本中,可以這樣寫:
FileName = str
def parse(file: FileName) -> None:
...
這裡 FileName 是基本 Python 字符串類型的別名。不過,從 Python 3.10開始,定義類型別名的語法將改為:
FileName: TypeAlias = str
def parse(file: FileName) -> None:
...
這個簡單的更改將使程式設計師和類型檢查器更容易區分普通變量賦值和類型別名。此更改也是向後兼容的,因此你不必更新任何使用類型別名的現有代碼。
除了這兩個變化之外,類型模塊還有其他改進 —— 即 PEP 612 中的參數規範變量(Parameter Specification Variables)。但是,這種代碼在大多數 Python 代碼庫中並不常見,因為它們用於將一個可調用(callable)的參數類型轉給另一個可調用的參數類型(例如在 decorator 中)。如果你有這樣的用例,請查看上面提到的 PEP。
數量統計(Population Count)從 Python 3.10 開始,你可以使用 int.bit_count() 來計算整數的二進位表示形式的位計數(1的數量)。這也被稱為數量統計(Population Count/popcount):
value = 42
print(bin(value))
# '0b101010'
print(value.bit_count())
# 3
這當然很好,但是呢,其實實現這個函數一點都不難,只需一行代碼:
def bit_count(value):
return bin(value).count("1")
儘管如此,這是又一個方便的函數,在某些時候可能會派上用場,而這些有用的小特性正是 Python 如此受歡迎的原因之一,似乎所有東西都是開箱即用的。
Distutils 被棄用(Deprecated)在新版本中,不只是添加了一些新東西,而且還棄用/刪除了一些東西。這包括 distutils 包,該包在 3.10 中已被棄用,將在 3.12 中移除。這個包已經被 setuptools 和 packaging 替代一段時間了,所以如果你使用這兩個工具中的任何一個,那麼應該沒有問題。儘管如此,你還是應該檢查代碼中 distutils 的使用情況,並開始準備在不久的將來擺脫它。
上下文管理器(Context Manager)語法Python 上下文管理器對於打開/關閉文件、處理資料庫連接和很多其他事情都非常有用,在 Python 3.10 中,它們的語法將有一點高質量的改進。這個改變允許帶圓括號的上下文管理器跨多行,如果你想用一個 with 語句創建多行,這是很方便的:
with (
open("somefile.txt") as some_file,
open("otherfile.txt") as other_file,
):
...
from contextlib import redirect_stdout
with (open("somefile.txt", "w") as some_file,
redirect_stdout(some_file)):
...
從上面可以看到,我們甚至可以在緊接著的另一個上下文管理器中引用由上一個上下文管理器(... as some_file)創建的的變量!
這些只是 Python 3.10 中可用的很多新格式中的兩種。這個改進後的語法非常靈活,所以我不打算展示每一個可能的格式選項,因為我非常確定無論你將在 Python 3.10 中使用什麼,它都很可能能正常工作。
性能提升正如最近發布的所有 Python 版本一樣,Python 3.10 也帶來了一些性能提升。首先是對 str()、 bytes() 和 bytearray() 構造函數的優化,它們的速度應該快 30% 左右(代碼段改編自 Python bug tracker 示例):
~ $ ./python3.10 -m pyperf timeit -q --compare-to=python "str()"
Mean +- std dev: [python] 81.9 ns +- 4.5 ns -> [python3.10] 60.0 ns +- 1.9 ns: 1.36x faster (-27%)
~ $ ./python3.10 -m pyperf timeit -q --compare-to=python "bytes()"
Mean +- std dev: [python] 85.1 ns +- 2.2 ns -> [python3.10] 60.2 ns +- 2.3 ns: 1.41x faster (-29%)
~ $ ./python3.10 -m pyperf timeit -q --compare-to=python "bytearray()"
Mean +- std dev: [python] 93.5 ns +- 2.1 ns -> [python3.10] 73.1 ns +- 1.8 ns: 1.28x faster (-22%)
另一個更值得注意的優化(如果你使用類型注釋)是函數參數及其注釋不再在運行時(runtime)計算,而是在編譯時計算。這使得創建一個帶有參數注釋的函數的速度提高了大約2倍。
除此之外,Python 核心的各個部分還有更多的優化。你可以在 Python bug tracker 的下列問題中找到更多的細節: bpo-41718、 bpo-42927 和 bpo-43452。
模式匹配(Pattern Matching)你肯定已經聽說過的一個重要特性是結構模式匹配(Structural Pattern Matching)。我們都知道其他程式語言如何使用 switch/case 語句,但考慮到這是 Python,嗯,它不僅僅是簡單的 switch/case 語法,而且還添加了一些強大的功能,我們應該研究研究。
模式匹配最基本的形式是由 match 關鍵詞和表達式組成,然後根據接著的 case 語句中的模式測試得出結果:
def func(day):
match day:
case "Monday":
return "Here we go again..."
case "Friday":
return "Happy Friday!"
case "Saturday" | "Sunday": # Multiple literals can be combined with `|`
return "Yay, weekend!"
case _:
return "Just another day..."
在這個簡單的示例中,我們使用 day 變量作為表達式,然後將其與 case 語句中的單個字符串進行比較。除了字符串字面值的情況外,你還會注意到最後一種情況,它使用 _ 通配符,這相當於其他語言中存在的默認關鍵詞。不過,這個通配符可以省略,在這種情況下實際上返回 None。
在上面的代碼中需要注意的另一點是 | 的使用,這使得使用 | (或)操作符組合多個文本成為可能。
正如我所提到的,這個新的模式匹配並不只有基本的語法,而是帶來了一些額外的特性,比如複雜模式的匹配:
def func(person): # person = (name, age, gender)
match person:
case (name, _, "male"):
print(f"{name} is man.")
case (name, _, "female"):
print(f"{name} is woman.")
case (name, age, gender):
print(f"{name} is {age} old.")
func(("John", 25, "male"))
# John is man.
在上面的代碼段中,我們使用元組作為要匹配的表達式。然而這並不局限於元組,任何可迭代對象 iterable 都可以工作。另外,正如上面看到的,_ 通配符也可以在複雜模式中使用,而不僅僅是像前面的示例中那樣單獨使用。
使用純元組或列表可能並不總是最好的方法,所以如果你更喜歡使用類,那麼可以用下面的方法重寫:
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
gender: str
def func(person): # person is instance of `Person` class
match person:
# This is not a constructor
case Person(name, age, gender) if age < 18: # guard for extra filtering
print(f"{name} is a child.")
case Person(name=name, age=_, gender="male"): # Wildcard ("throwaway" variable) can be used
print(f"{name} is man.")
case Person(name=name, age=_, gender="female"):
print(f"{name} is woman.")
case Person(name, age, gender): # Positional arguments work
print(f"{name} is {age} years old.")
func(Person("Lucy", 30, "female"))
# Lucy is woman.
func(Person("Ben", 15, "male"))
# Ben is a child.
這裡我們可以使用類似類構造函數的模式來匹配類的屬性。當使用這種方法時,還可以將單個屬性捕獲到變量中(與前面展示的元組一樣),然後我們可以在各自的 case 主體中使用。
上面我們還可以看到模式匹配的一些其他特性,比如在第一個 case 語句中,它是一個嚮導,這是一個遵循模式的 if 條件。如果按值進行匹配還不夠,需要添加一些附加的條件檢查,那麼這種方法會很有用。再看看其他情況,我們還可以看到關鍵詞(例如 name = name)和位置參數都可以使用類似構造函數的語法,對於 _ 變量也是如此。
模式匹配還允許使用嵌套模式。這些嵌套模式可以使用任何可迭代對象,包括類似構造函數的對象或對象內更多的可迭代對象:
match users:
case [Person(...)]:
print("One user provided...")
case [Person(...), Person(...) as second]: # `as var` can be used to capture subpattern
print(f"There's another user: {second}")
case [Person(...), Person(...), *rest]: # `*var` can be used as unpacking
print(...)
這種複雜模式中,將子模式捕獲到變量中以便進行進一步處理可能非常有用。這可以通過使用 as 關鍵詞來完成,如上面第二個 case 所示。
最後,* 操作符可用於「解壓縮(unpack)」模式中的變量,_ 通配符也可以使用 *_ 模式。
如果你想看到更多的例子和完整的教程,請查看 PEP 636。
最後Python 3.10 帶來了很多有趣的新特性,但這是 alpha 版(下個月即將發布 beta 版),還沒經過充分的測試。因此,現在就開始在生產中使用它絕對不是一個好主意。所以,最好坐等10月份的正式版發布,有空就刷刷 Python 3.10 新聞頁面。
話雖如此,用第一個 beta 版本(將在5月3號發布)進行測試運行,看看你現有的代碼庫是否與所有即將到來的更改、棄用或刪除的函數/模塊兼容,這當然是個未雨綢繆的好主意。
原文: https://towardsdatascience.com/all-the-important-features-and-changes-in-python-3-10-e3d1fe542fbf
更多視覺圖像處理相關內容,請長按關注:OpenCV與AI深度學習。
覺得有用,麻煩給個贊和在看