Python 类型提示 Type Hints 怎么用?

文章导读
Previous Quiz Next Python 类型提示 在 PEP 484 中引入,为动态类型语言带来了静态类型的好处。虽然类型提示不会在运行时强制执行类型检查,但它们提供了一种指定变量、函数参数和返回值预期类型的方法,可以由静态分析工具如 mypy 进行检查。这提高
📋 目录
  1. Different Types of Type Hints in Python
  2. 基本数据类型
  3. 集合类型
  4. Optional 类型
  5. Union 类型
  6. Any 类型
  7. 类型别名
  8. 泛型类型
  9. 可调用类型
  10. 字面量类型
A A

Python - 类型提示



Previous
Quiz
Next

Python 类型提示 在 PEP 484 中引入,为动态类型语言带来了静态类型的好处。虽然类型提示不会在运行时强制执行类型检查,但它们提供了一种指定变量、函数参数和返回值预期类型的方法,可以由静态分析工具如 mypy 进行检查。这提高了代码的可读性,便于调试,并提升了代码的整体可维护性。

Python 中的 类型提示 使用注解来标注函数参数、返回值和变量赋值。

Python 的 类型提示 可用于指定各种类型,如基本数据类型、集合、复杂类型和自定义用户定义类型。typing 模块提供了许多内置类型来表示这些各种类型 −

  • 基本数据类型
  • 集合类型
  • 可选类型
  • 联合类型
  • 任意类型
  • 类型别名
  • 泛型
  • 可调用类型
  • 字面量类型
  • NewType

我们将逐一详细介绍它们。

基本数据类型

在 Python 中,使用 类型提示 指定基本类型时,可以直接使用类型名称作为注解。

示例

以下是使用基本数据类型如 integer、float、string 等类型的示例 −

from typing import Optional

# 整数类型
def calculate_square_area(side_length: int) -> int:
   return side_length ** 2

# 浮点数类型
def calculate_circle_area(radius: float) -> float:
   return 3.14 * radius * radius

# 字符串类型
def greet(name: str) -> str:
   return f"Hello, {name}"

# 布尔类型
def is_adult(age: int) -> bool:
   return age >= 18

# None 类型
def no_return_example() -> None:
   print("This function does not return anything")

# 可选类型 (int 或 None 的联合)
def safe_divide(x: int, y: Optional[int]) -> Optional[float]:
   if y is None or y == 0:
      return None
   else:
      return x / y

# 示例用法
print(calculate_square_area(5))        
print(calculate_circle_area(3.0))     
print(greet("Alice"))                 
print(is_adult(22))                   
no_return_example()                   
print(safe_divide(10, 2))             
print(safe_divide(10, 0))             
print(safe_divide(10, None))          

执行上述代码将得到以下 输出

25
28.259999999999998
Hello, Alice
True
This function does not return anything
5.0
None
None

集合类型

在 Python 中处理集合(如 lists、tuples、dictionaries 等)时,在 type hints 中我们通常使用 typing 模块来指定集合类型。

示例

下面是使用 type hints 的集合示例 −

from typing import List, Tuple, Dict, Set, Iterable, Generator

# 整数列表
def process_numbers(numbers: List[int]) -> List[int]:
   return [num * 2 for num in numbers]

# 浮点数元组
def coordinates() -> Tuple[float, float]:
   return (3.0, 4.0)

# 字符串键和整数值的字典
def frequency_count(items: List[str]) -> Dict[str, int]:
   freq = {}
   for item in items:
      freq[item] = freq.get(item, 0) + 1
   return freq

# 字符串中唯一字符的集合
def unique_characters(word: str) -> Set[str]:
   return set(word)

# 整数的可迭代对象
def print_items(items: Iterable[int]) -> None:
   for item in items:
      print(item)

# 生成器,产生从 0 到 n 的整数平方
def squares(n: int) -> Generator[int, None, None]:
   for i in range(n):
      yield i * i

# 示例用法
numbers = [1, 2, 3, 4, 5]
print(process_numbers(numbers))                   

print(coordinates())                            

items = ["apple", "banana", "apple", "orange"]
print(frequency_count(items))                    

word = "hello"
print(unique_characters(word))                   

print_items(range(5))                           

gen = squares(5)
print(list(gen))                                          

执行上述代码将得到以下 输出

[2, 4, 6, 8, 10]
(3.0, 4.0)
{'apple': 2, 'banana': 1, 'orange': 1}
{'l', 'e', 'h', 'o'}
0
1
2
3
4
[0, 1, 4, 9, 16]

Optional 类型

在 Python 中,Optional 类型 用于表示变量可以是指定类型或 None。这在函数可能不总是返回值或参数可以接受值或留空时特别有用。

示例

以下是使用 Optional 类型type hints 中的示例 −

from typing import Optional

def divide(a: float, b: float) -> Optional[float]:
   if b == 0:
      return None
   else:
      return a / b

result1: Optional[float] = divide(10.0, 2.0)   # result1 将是 5.0
result2: Optional[float] = divide(10.0, 0.0)   # result2 将是 None

print(result1)  
print(result2)                                           

执行上述代码将得到以下 输出

5.0
None

Union 类型

Python 使用 Union 类型允许变量接受不同类型的数值。这在函数或数据结构可以处理各种类型的输入或产生不同类型的输出时很有用。

示例

以下是示例 −

from typing import Union

def square_root_or_none(number: Union[int, float]) -> Union[float, None]:
   if number >= 0:
      return number ** 0.5
   else:
      return None

result1: Union[float, None] = square_root_or_none(50)   
result2: Union[float, None] = square_root_or_none(-50)  

print(result1)  
print(result2)                                             

执行上述代码将得到以下 输出

7.0710678118654755
None

Any 类型

在 Python 中,Any 类型 是一种特殊的 type hint,表示变量可以是任意类型。它本质上禁用了该变量或表达式的类型检查。这在值类型事先未知或处理动态数据时很有用。

示例

以下是使用 Any 类型在 type hint 中的示例 −

from typing import Any

def print_value(value: Any) -> None:
   print(value)

print_value(10)         
print_value("hello")    
print_value(True)       
print_value([1, 2, 3])  
print_value({'key': 'value'})                                           

执行上述代码将得到以下 输出

10
hello
True
[1, 2, 3]
{'key': 'value'}

类型别名

类型别名在 Python 中用于为现有类型提供替代名称。它们可以通过为复杂的类型注解或类型组合提供清晰的名称,使代码更容易阅读。这在处理嵌套结构或长类型提示时特别有用。

示例

下面是在 类型提示中使用 类型别名 的示例 −

from typing import List, Tuple

# 定义整数列表的类型别名
Vector = List[int]

# 定义坐标元组的类型别名
Coordinates = Tuple[float, float]

# 使用类型别名的函数
def scale_vector(vector: Vector, factor: float) -> Vector:
    return [int(num * factor) for num in vector]

def calculate_distance(coord1: Coordinates, coord2: Coordinates) -> float:
   x1, y1 = coord1
   x2, y2 = coord2
   return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5

# 使用类型别名
v: Vector = [1, 2, 3, 4]
scaled_v: Vector = scale_vector(v, 2.5)
print(scaled_v)  

c1: Coordinates = (3.0, 4.0)
c2: Coordinates = (6.0, 8.0)
distance: float = calculate_distance(c1, c2)
print(distance)                                             

执行上述代码将得到以下 输出

[2, 5, 7, 10]
5.0

泛型类型

泛型类型用于创建函数、class 或数据结构,使其能够处理任意类型,同时保持类型安全。typing 模块中的 TypeVar 和 Generic 构造使得这一点成为可能。它们有助于创建可重用的组件,能够与各种类型协作,而不影响类型检查。

示例

以下是其示例 −

from typing import TypeVar, List

# 定义类型变量 T
T = TypeVar('T')

# 返回列表第一个元素的泛型函数
def first_element(items: List[T]) -> T:
   return items[0]

# 示例用法
int_list = [1, 2, 3, 4, 5]
str_list = ["apple", "banana", "cherry"]

first_int = first_element(int_list)      # first_int 将是 int 类型
first_str = first_element(str_list)      # first_str 将是 str 类型

print(first_int)    
print(first_str)                                              

执行上述代码将得到以下 输出

1
apple

可调用类型

Python 的 Callable 类型用于表示某类型是函数或可调用对象。它位于 typing 模块中,允许您定义函数的参数类型和返回类型。这对于高阶函数非常有用。

示例

以下是在 type hint 中使用 Callable 类型示例 −

from typing import Callable

# 定义一个接受另一个函数作为参数的函数
def apply_operation(x: int, y: int, operation: Callable[[int, int], int]) -> int:
   return operation(x, y)

# 作为参数传递的示例函数
def add(a: int, b: int) -> int:
   return a + b

def multiply(a: int, b: int) -> int:
   return a * b

# 使用 apply_operation 函数与不同操作
result1 = apply_operation(5, 3, add)        # result1 将是 8
result2 = apply_operation(5, 3, multiply)   # result2 将是 15

print(result1)  
print(result2)                                                

执行上述代码将得到以下 输出

8
15

字面量类型

Literal 类型用于指定值必须精确匹配一组预定义值中的某一个。

示例

以下是示例 −

from typing import Literal

def move(direction: Literal["left", "right", "up", "down"]) -> None:
   print(f"Moving {direction}")

move("left")  # 有效
move("up")    # 有效                                     

执行上述代码将得到以下 输出

Moving left
Moving up

NewType

NewTypetyping 模块中的一个函数,它允许我们从现有类型创建出不同的类型。这可以通过区分同一底层类型不同用途来为代码添加类型安全性。例如,我们可能希望区分用户 ID 和产品 ID,尽管两者都表示为整数。

示例

以下是示例 −

from typing import NewType

# 创建新类型
UserId = NewType('UserId', int)
ProductId = NewType('ProductId', int)

# 定义使用新类型的函数
def get_user_name(user_id: UserId) -> str:
   return f"User with ID {user_id}"

def get_product_name(product_id: ProductId) -> str:
   return f"Product with ID {product_id}"

# 示例用法
user_id = UserId(42)
product_id = ProductId(101)

print(get_user_name(user_id))   # 输出: User with ID 42
print(get_product_name(product_id))  # 输出: Product with ID 101                                   

执行上述代码后,我们将得到以下输出

User with ID 42
Product with ID 101