Python類型系統(tǒng)typing模塊示例詳解
1. 模塊概述
typing
模塊在 Python 3.5 中引入,用于支持類型提示(Type Hints)。它提供了:
- 用于類型注釋的工具
- 泛型類型支持
- 類型別名
- 回調(diào)協(xié)議
- 以及其他高級(jí)類型系統(tǒng)特性
2. 基礎(chǔ)類型提示
2.1 基本類型注釋
from typing import List, Dict, Set, Tuple, Optional # 變量類型注釋 name: str = "Alice" age: int = 30 is_student: bool = False # 函數(shù)參數(shù)和返回值類型注釋 def greet(name: str) -> str: return f"Hello, {name}" # 容器類型 numbers: List[int] = [1, 2, 3] person: Dict[str, str] = {"name": "Alice", "email": "alice@example.com"} unique_numbers: Set[int] = {1, 2, 3} coordinates: Tuple[float, float] = (10.5, 20.3) # 可選類型 maybe_name: Optional[str] = None # 等同于 Union[str, None]
2.2 類型別名
from typing import List, Tuple # 創(chuàng)建類型別名 Vector = List[float] Point = Tuple[float, float] def scale_vector(v: Vector, factor: float) -> Vector: return [x * factor for x in v] def distance(p1: Point, p2: Point) -> float: return ((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)**0.5
3. 復(fù)合類型
3.1 Union 類型
- 表示屬于Union中的任意一種類型均合法
from typing import Union def process_value(value: Union[int, str]) -> None: if isinstance(value, int): print(f"Processing integer: {value}") else: print(f"Processing string: {value}") process_value(10) # Processing integer: 10 process_value("hi") # Processing string: hi
3.2 Optional 類型
- Optional[str] = Union[str, None]
from typing import Optional def find_user(user_id: int) -> Optional[str]: users = {1: "Alice", 2: "Bob"} return users.get(user_id) print(find_user(1)) # Alice print(find_user(3)) # None
3.3 Any 類型
- 表示可以使用任何類型,不建議常用
from typing import Any def process_any(value: Any) -> Any: print(f"Processing {value}") return value result = process_any(10) # Processing 10 result = process_any("text") # Processing text
4. 泛型類型
4.1 TypeVar
from typing import TypeVar, List, Sequence T = TypeVar('T') # 任意類型 Num = TypeVar('Num', int, float) # 僅限于int和float def first_element(items: Sequence[T]) -> T: return items[0] print(first_element([1, 2, 3])) # 1 print(first_element(["a", "b"])) # a
4.2 Generic 類
from typing import TypeVar, Generic, List T = TypeVar('T') class Stack(Generic[T]): def __init__(self) -> None: self.items: List[T] = [] def push(self, item: T) -> None: self.items.append(item) def pop(self) -> T: return self.items.pop() int_stack = Stack[int]() int_stack.push(1) int_stack.push(2) print(int_stack.pop()) # 2
5. 函數(shù)類型
5.1 Callable
from typing import Callable def apply_func(func: Callable[[int, int], int], a: int, b: int) -> int: return func(a, b) def add(x: int, y: int) -> int: return x + y print(apply_func(add, 3, 5)) # 8
5.2 可調(diào)用對(duì)象協(xié)議
from typing import Protocol class Adder(Protocol): def __call__(self, a: int, b: int) -> int: ... def apply_adder(adder: Adder, x: int, y: int) -> int: return adder(x, y) print(apply_adder(lambda a, b: a + b, 10, 20)) # 30
6. 帶元數(shù)據(jù)的類型Annotated
Annotated
是 Python typing
模塊中一個(gè)強(qiáng)大但常被忽視的類型注解工具,它允許我們?cè)陬愋吞崾局刑砑宇~外的元數(shù)據(jù)。這個(gè)功能在 Python 3.9 中引入,為類型系統(tǒng)提供了更大的靈活性。Annotated
的基本形式如下:
from typing import Annotated Annotated[<type>, <metadata1>, <metadata2>, ...]
其中:
<type>
是基礎(chǔ)類型<metadata>
可以是任意對(duì)象,提供額外的類型信息
6.1 基本示例
from typing import Annotated # 給int類型添加單位信息 Distance = Annotated[int, "meters"] Temperature = Annotated[float, "celsius"] def get_distance() -> Distance: return 100 def get_temperature() -> Temperature: return 25.5
6.2 核心特性
- 保留類型信息
Annotated
不會(huì)改變?cè)碱愋停皇歉郊釉獢?shù)據(jù):
from typing import Annotated, get_type_hints UserId = Annotated[int, "user identifier"] def get_user(id: UserId) -> str: return f"user_{id}" # 獲取類型提示 hints = get_type_hints(get_user) print(hints) # {'id': typing.Annotated[int, 'user identifier'], 'return': <class 'str'>}
- 多重元數(shù)據(jù)
可以附加多個(gè)元數(shù)據(jù)項(xiàng):
from typing import Annotated # 帶有范圍和單位的溫度類型 BoundedTemp = Annotated[float, "celsius", (0.0, 100.0)] def check_temp(temp: BoundedTemp) -> bool: return 0.0 <= temp <= 100.0
6.3 應(yīng)用場(chǎng)景
- 數(shù)據(jù)驗(yàn)證
結(jié)合 Pydantic 等庫(kù)進(jìn)行數(shù)據(jù)驗(yàn)證:
from typing import Annotated from pydantic import BaseModel, Field PositiveInt = Annotated[int, Field(gt=0)] class User(BaseModel): id: PositiveInt name: str # 有效數(shù)據(jù) user = User(id=1, name="Alice") # 無效數(shù)據(jù)會(huì)引發(fā)驗(yàn)證錯(cuò)誤 # user = User(id=-1, name="Bob") # 拋出ValidationError
- 參數(shù)約束
在 FastAPI 等框架中指定參數(shù)約束:
from typing import Annotated from fastapi import FastAPI, Query app = FastAPI() @app.get("/items/") async def read_items( q: Annotated[str, Query(min_length=3, max_length=50)] = "default" ): return {"q": q}
- 文檔增強(qiáng)
為類型添加文檔信息:
from typing import Annotated from typing_extensions import Doc # Python 3.11+ DatabaseConnection = Annotated[ str, Doc("A connection string in the format 'user:password@host:port/database'"), Doc("Example: 'admin:secret@localhost:5432/mydb'") ] def connect_db(conn_str: DatabaseConnection) -> None: """Connect to the database.""" print(f"Connecting with: {conn_str}")
6.4 與其他類型工具結(jié)合
- 與 NewType 結(jié)合
from typing import Annotated, NewType UserId = NewType('UserId', int) AnnotatedUserId = Annotated[UserId, "primary key"] def get_user_name(user_id: AnnotatedUserId) -> str: return f"user_{user_id}" print(get_user_name(UserId(42))) # user_42
- 與 Literal 結(jié)合
from typing import Annotated, Literal HttpMethod = Literal["GET", "POST", "PUT", "DELETE"] AnnotatedHttpMethod = Annotated[HttpMethod, "HTTP method"] def log_request(method: AnnotatedHttpMethod) -> None: print(f"Received {method} request") log_request("GET") # 有效 # log_request("HEAD") # 類型檢查器會(huì)報(bào)錯(cuò)
6.5 運(yùn)行時(shí)訪問元數(shù)據(jù)
from typing import Annotated, get_type_hints def extract_metadata(annotated_type): origin = get_origin(annotated_type) if origin is not Annotated: return None return get_args(annotated_type)[1:] # 返回元數(shù)據(jù)部分 # 定義帶注解的類型 Count = Annotated[int, "counter", "must be positive"] hints = get_type_hints(lambda x: x, localns={'x': Count}) metadata = extract_metadata(hints['x']) print(metadata) # ('counter', 'must be positive')
6.6. 實(shí)際案例:數(shù)據(jù)庫(kù)字段類型
from typing import Annotated, Optional from datetime import datetime # 定義帶約束的字段類型 Username = Annotated[str, "username", "max_length=32", "alphanumeric"] Email = Annotated[str, "email", "max_length=255"] CreatedAt = Annotated[datetime, "auto_now_add=True"] UpdatedAt = Annotated[Optional[datetime], "auto_now=True", "nullable=True"] class UserProfile: def __init__( self, username: Username, email: Email, created_at: CreatedAt, updated_at: UpdatedAt = None ): self.username = username self.email = email self.created_at = created_at self.updated_at = updated_at # 這些注解可以被ORM框架或序列化庫(kù)讀取并使用
Annotated
為 Python 的類型系統(tǒng)提供了強(qiáng)大的擴(kuò)展能力,使得類型提示不僅可以用于靜態(tài)檢查,還能攜帶豐富的運(yùn)行時(shí)信息,為框架開發(fā)和復(fù)雜系統(tǒng)設(shè)計(jì)提供了更多可能性。
7. 高級(jí)類型特性
7.1 Literal 類型
from typing import Literal def draw_shape(shape: Literal["circle", "square", "triangle"]) -> None: print(f"Drawing a {shape}") draw_shape("circle") # 正確 draw_shape("square") # 正確 # draw_shape("rectangle") # 類型檢查器會(huì)報(bào)錯(cuò)
7.2 TypedDict
from typing import TypedDict, Optional class Person(TypedDict): name: str age: int email: Optional[str] alice: Person = {"name": "Alice", "age": 30} bob: Person = {"name": "Bob", "age": 25, "email": "bob@example.com"}
7.3 NewType
from typing import NewType UserId = NewType('UserId', int) admin_id = UserId(1) def get_user_name(user_id: UserId) -> str: return f"user_{user_id}" print(get_user_name(admin_id)) # 正確 # print(get_user_name(12345)) # 類型檢查器會(huì)報(bào)錯(cuò)
8. 運(yùn)行時(shí)類型檢查
8.1 typeguard
雖然 typing
模塊主要用于靜態(tài)類型檢查,但可以與第三方庫(kù)如 typeguard
結(jié)合實(shí)現(xiàn)運(yùn)行時(shí)檢查:
from typeguard import typechecked from typing import List @typechecked def process_numbers(numbers: List[int]) -> float: return sum(numbers) / len(numbers) print(process_numbers([1, 2, 3])) # 2.0 # process_numbers([1, '2', 3]) # 運(yùn)行時(shí)拋出TypeError
8.2 get_type_hints
from typing import get_type_hints, List, Dict def example(a: int, b: str = "default") -> Dict[str, List[int]]: return {b: [a]} print(get_type_hints(example)) # 輸出: {'a': <class 'int'>, 'b': <class 'str'>, 'return': Dict[str, List[int]]}
9. Python 3.10+ 新特性
9.1 聯(lián)合類型語(yǔ)法糖
# Python 3.10 之前 from typing import Union def old_way(x: Union[int, str]) -> Union[int, str]: return x # Python 3.10+ def new_way(x: int | str) -> int | str: return x
9.2 TypeGuard
from typing import TypeGuard, List, Union def is_str_list(val: List[Union[str, int]]) -> TypeGuard[List[str]]: return all(isinstance(x, str) for x in val) def process_items(items: List[Union[str, int]]) -> None: if is_str_list(items): print("All strings:", [s.upper() for s in items]) else: print("Mixed types:", items) process_items(["a", "b", "c"]) # All strings: ['A', 'B', 'C'] process_items([1, "b", 3]) # Mixed types: [1, 'b', 3]
10. 遷移策略
10.1 逐步添加類型提示
# 第一階段:無類型提示 def old_function(x): return x * 2 # 第二階段:添加簡(jiǎn)單類型提示 def partially_typed_function(x: int) -> int: return x * 2 # 第三階段:完整類型提示 from typing import TypeVar, Sequence T = TypeVar('T') def fully_typed_function(items: Sequence[T], multiplier: int) -> list[T]: return [item * multiplier for item in items]
10.2 處理動(dòng)態(tài)類型代碼
import types from typing import Any, Union, cast def dynamic_function(func: Union[types.FunctionType, types.BuiltinFunctionType]) -> Any: result = func() # 如果我們知道特定函數(shù)的返回類型,可以使用cast if func.__name__ == 'get_answer': return cast(int, result) return result
typing 模塊總結(jié)
- 為 Python 添加靜態(tài)類型提示支持
- 提供豐富的類型注解工具(
List
,Dict
,Union
等) - 支持泛型編程(
TypeVar
,Generic
) - 包含高級(jí)類型特性(
Literal
,TypedDict
,Protocol
等) - 與 Python 3.10+ 的新語(yǔ)法(
|
運(yùn)算符)良好集成 - 類型提示在運(yùn)行時(shí)幾乎沒有性能影響,因?yàn)樗鼈冎饕混o態(tài)類型檢查器使用
typing
模塊中的一些特殊形式(如Generic
)可能會(huì)引入輕微的開銷- 在性能關(guān)鍵代碼中,考慮使用簡(jiǎn)單的類型提示或僅在開發(fā)時(shí)使用類型檢查
總結(jié)
到此這篇關(guān)于Python類型系統(tǒng)typing模塊示例詳解的文章就介紹到這了,更多相關(guān)Python類型系統(tǒng)typing模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python PyInstaller庫(kù)基本使用方法分析
這篇文章主要介紹了Python PyInstaller庫(kù)基本使用方法,結(jié)合實(shí)例形式分析了Python PyInstaller庫(kù)的功能、安裝及相關(guān)使用注意事項(xiàng),需要的朋友可以參考下2019-12-12使用matplotlib創(chuàng)建Gif動(dòng)圖的實(shí)現(xiàn)
本文主要介紹了使用matplotlib創(chuàng)建Gif動(dòng)圖的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04推薦10款最受Python開發(fā)者歡迎的Python IDE
這篇文章收集了一些對(duì)開發(fā)者非常有幫助的,最好的10款Python IDE,包括Vim,Eclipse with PyDev,Sublime Text,PyCharm等知明Python開發(fā)工具2018-09-09django進(jìn)階之cookie和session的使用示例
這篇文章主要介紹了django進(jìn)階之cookie和session的使用示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08Python?matplotlib繪圖時(shí)使用鼠標(biāo)滾輪放大/縮小圖像
Matplotlib是Python程序員可用的事實(shí)上的繪圖庫(kù),雖然它比交互式繪圖庫(kù)在圖形上更簡(jiǎn)單,但它仍然可以一個(gè)強(qiáng)大的工具,下面這篇文章主要給大家介紹了關(guān)于Python?matplotlib繪圖時(shí)使用鼠標(biāo)滾輪放大/縮小圖像的相關(guān)資料,需要的朋友可以參考下2022-05-05利用Python演示數(shù)型數(shù)據(jù)結(jié)構(gòu)的教程
這篇文章主要介紹了利用Python演示數(shù)型數(shù)據(jù)結(jié)構(gòu)的教程,核心代碼其實(shí)只有一行(XD),需要的朋友可以參考下2015-04-04