Python中型別提示的最佳實踐

王林
發布: 2023-04-23 09:28:06
轉載
1499 人瀏覽過

使用動態語言一時爽,程式碼重構火葬場。相信你一定聽過這句話,和單元測試一樣,雖然寫程式碼的時候花費你少量的時間,但是從長遠來看,這是非常值得的。本文分享如何更好的理解和使用 Python 的類型提示。

1、類型提示僅在語法層面有效

類型提示(自PEP 3107 開始引入)用於向變數、參數、函數參數以及它們的返回值、類別屬性和方法添加類型。

Python 的變數類型是動態的,可以在運行時修改,為程式碼添加類型提示,僅在語法層面支持,對程式碼的運行沒有任何影響,Python 解釋器在運行程式碼的時候會忽略類型提示。

因此型別提示一個直覺的作用就是提升程式碼的可讀性,方便呼叫者傳入/傳出適當型別的參數,便於程式碼重構。

Python 內建的基本類型可以直接用於類型提示:

變數的類型提示範例:

a: int = 3
b: float = 2.4
c: bool = True
d: list = ["A", "B", "C"]
e: dict = {"x": "y"}
f: set = {"a", "b", "c"}
g: tuple = ("name", "age", "job")
登入後複製

函數的類型提示:

def add_numbers(x: type_x, y: type_y, z: type_z= 100) -> type_return:
return x + y + z
登入後複製

這裡的type_x , type_y , type_z , type_return 可以是內建的基本類型,也可以是自訂類型。

類別的型別提示:

class Person:
first_name: str = "John"
last_name: str = "Does"
age: int = 31
登入後複製

2、用mypy 檢查型別提示

假如有這樣一段程式碼:

x: int = 2

x = 3.5
登入後複製

用Python 解釋器執行是不會有任何錯誤的:

如何更好的使用 Python 的类型提示?

借助於mypy 就可以,先pip install mypy 安裝一下,然後mypy script.py 即可:

如何更好的使用 Python 的类型提示?

更多mypy 相關可以參考前文mypy 這個工具,讓Python的類型提示變得非常實用。

3、型別提示的好處

如果解釋器沒有強制執行型別提示,為什麼還要寫型別提示呢?確實,類型提示不會改變程式碼的運作方式:Python 本質上是動態類型的,這一點不太可能會改變。但是,從開發人員經驗的角度來看,類型提示有許多好處。

(1)、使用類型提示,尤其是在函數中,透過類型提示來明確參數類型和所產生結果的類型,非常便於閱讀和理解。

(2)、類型提示消除了認知開銷,並使程式碼更易於閱讀和除錯。考慮到輸入和輸出的類型,你可以輕鬆推斷物件以及它們如何調用。

(3)、類型提示可改善程式碼編輯體驗。 IDE 可以依靠類型偵測來靜態分析你的程式碼並幫助偵測潛在的錯誤(例如,傳遞錯誤類型的參數、呼叫錯誤的方法等)。另外,也可以根據類型提示為每個變數提供自動補全。

如何更好的使用 Python 的类型提示?

IDE 的類型檢查

如何更好的使用 Python 的类型提示?

#IDE 的類型檢查

如何更好的使用 Python 的类型提示?

IDE 類型檢查後的自動補全

4、List 用法

假如你需要列表list 內部是float 的類型提示,這樣做是不行的:

def my_dummy_function(l: list[float]):
 return sum(l)
登入後複製

標準函式庫typing 考慮到了這個問題,你可以這樣:

from typing import List

def my_dummy_function(vector: List[float]):
 return sum(vector)
登入後複製

5、Dict 用法

假如要提示這樣的類型:

my_dict = {"name": "Somenzz", "job": "engineer"}
登入後複製

借助於Dict,你可以這樣定義類型:

from typing import Dict
my_dict_type = Dict[str, str]
my_dict: my_dict_type = {"name": "Somenzz", "job": "engineer"}
登入後複製

6、TypedDict 用法

假如你需要提示這樣的類型,那該怎麼辦?

d = {"name": "Somenzz", "interests": ["chess", "tennis"]}
登入後複製

借助TypedDict ,你可以這樣:

如何更好的使用 Python 的类型提示?

TypedDict

7、Union 用法

從Python 3.10 開始,Union 被替換為| 這意味著Union[X, Y] 現在等價於X | Y。

Union[X, Y](或 X | Y)表示 X 或 Y。

假設你的函數需要從快取目錄中讀取檔案並載入 Torch 模型。此快取目錄位置可以是字串值(例如/home/cache ),也可以是Pathlib 庫的Path 對象,在這種情況下,程式碼如下:

def load_model(filename: str, cache_folder: Union[str, Path]):
if isinstance(cache_folder, Path):
cache_folder = str(cache_folder)

model_path = os.join(filename, cache_folder)
model = torch.load(model_path)
return model
登入後複製

##8、 Callable 用法

當你需要傳入一個函數當參數的時候,這個參數的型別提示可以為Callable。

from typing import Callable

def sum_numbers(x: int, y: int) -> int:
return x + y

def foo(x: int, y: int, func: Callable) -> int:
output = func(x, y)
return output

foo(1, 2, sum_numbers)
登入後複製

你也可以給這樣的函數參數指定參數列表,真的很強大:

語法:

Callable[[input_type_1, ...], return_type]
登入後複製

範例:

def foo(x: int, y: int, func: Callable[[int, int], int]) -> int:
output = func(x, y)
return output
登入後複製

9、Any 用法

当你传入的参数可以为任何类型的时候,就可以使用 Any

def bar(input: Any):
...
登入後複製

10、Optional 用法

如果你的函数使用可选参数,具有默认值,那么你可以使用类型模块中的 Optional 类型。

from typing import Optional

def foo(format_layout: Optional[bool] = True):
...
登入後複製

11、Sequence 用法

Sequence 类型的对象是可以被索引的任何东西:列表、元组、字符串、对象列表、元组列表的元组等。

from typing import Sequence

def print_sequence_elements(sequence: Sequence[str]):
for i, s in enumerate(s):
print(f"item {i}: {s}"
登入後複製

12、Tuple 用法

Tuple 类型的工作方式与 List 类型略有不同,Tuple 需要指定每一个位置的类型:

from typing import Tuple
t: Tuple[int, int, int] = (1, 2, 3)
登入後複製

如果你不关心元组中每个元素的类型,你可以继续使用内置类型 tuple。

t: tuple = (1, 2, 3, ["cat", "dog"], {"name": "John"})
登入後複製

最后的话

类型提示在代码之上带来了额外的抽象层:它们有助于记录代码,澄清关于输入/输出的假设,并防止在顶部执行静态代码分析 (mypy) 时出现的隐蔽和错误。

以上是Python中型別提示的最佳實踐的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:51cto.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板