Python 简明教程

Python - Type Hints

Python type hints 在 PEP 484 中引入,以便将静态类型的优势带入动态类型语言。尽管类型提示不会在运行时强制类型检查,但它们提供了一种指定 variables 、函数参数和返回值的预期类型的方法,静态分析工具(如 mypy )可以检查这些类型。这增强了代码的可读性,促进了调试,并提高了代码的整体可维护性。

Python 中的 Type hints 使用注释来表示函数参数、返回值和变量分配。

Python 的 type hints 可用于指定各种类型,如基本 data types 、集合、复杂类型和自定义用户定义类型。 typing 模块提供了许多用于表示这些不同类型的内置类型 -

让我们一一详细查看每个类型。

Basic Data Types

在 Python 中,在使用 type hints 来指定基本类型时,我们只需使用类型的名称作为注释即可。

Example

以下是使用基本数据类型(如整数、浮点数、字符串等)的示例 -

from typing import Optional

# Integer type
def calculate_square_area(side_length: int) -> int:
   return side_length ** 2

# Float type
def calculate_circle_area(radius: float) -> float:
   return 3.14 * radius * radius

# String type
def greet(name: str) -> str:
   return f"Hello, {name}"

# Boolean type
def is_adult(age: int) -> bool:
   return age >= 18

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

# Optional type (Union of int or None)
def safe_divide(x: int, y: Optional[int]) -> Optional[float]:
   if y is None or y == 0:
      return None
   else:
      return x / y

# Example usage
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))

执行以上代码,我们将获得以下 output -

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

Collections Types

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

Example

以下是 type hints 中使用集合的示例 -

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

# List of integers
def process_numbers(numbers: List[int]) -> List[int]:
   return [num * 2 for num in numbers]

# Tuple of floats
def coordinates() -> Tuple[float, float]:
   return (3.0, 4.0)

# Dictionary with string keys and integer values
def frequency_count(items: List[str]) -> Dict[str, int]:
   freq = {}
   for item in items:
      freq[item] = freq.get(item, 0) + 1
   return freq

# Set of unique characters in a string
def unique_characters(word: str) -> Set[str]:
   return set(word)

# Iterable of integers
def print_items(items: Iterable[int]) -> None:
   for item in items:
      print(item)

# Generator yielding squares of integers up to n
def squares(n: int) -> Generator[int, None, None]:
   for i in range(n):
      yield i * i

# Example usage
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))

执行以上代码,我们将获得以下 output -

[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 Types

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

Example

以下是在 type hints 中使用 optional types 的示例 −

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 will be 5.0
result2: Optional[float] = divide(10.0, 0.0)   # result2 will be None

print(result1)
print(result2)

执行以上代码,我们将获得以下 output -

5.0
None

Union Types

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

Example

以下是示例 −

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)

执行以上代码,我们将获得以下 output -

7.0710678118654755
None

Any Type

在 Python 中, Any type 是一个特殊类型提示,表示变量可以是任何类型。它本质上禁止了对特定变量或表达式的类型检查。这在事前不知道值类型或处理动态数据时很有用。

Example

以下是 Type hint 中使用 Any 类型示例 −

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'})

执行以上代码,我们将获得以下 output -

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

Type Aliases

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

Example

以下是 Type hints 中使用 Type Aliases 的示例 −

from typing import List, Tuple

# Define a type alias for a list of integers
Vector = List[int]

# Define a type alias for a tuple of coordinates
Coordinates = Tuple[float, float]

# Function using the type aliases
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

# Using the type aliases
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)

执行以上代码,我们将获得以下 output -

[2, 5, 7, 10]
5.0

Generic Types

Generic types 创建可以处理任何类型的函数、类或数据结构,同时保持类型安全。typing 模块的 TypeVar 和 Generic 构造使这成为可能。它们有助于制作可与各种类型配合使用的可重用组件,而不会损害类型检查。

Example

以下是示例 −

from typing import TypeVar, List

# Define a type variable T
T = TypeVar('T')

# Generic function that returns the first element of a list
def first_element(items: List[T]) -> T:
   return items[0]

# Example usage
int_list = [1, 2, 3, 4, 5]
str_list = ["apple", "banana", "cherry"]

first_int = first_element(int_list)      # first_int will be of type int
first_str = first_element(str_list)      # first_str will be of type str

print(first_int)
print(first_str)

执行以上代码,我们将获得以下 output -

1
apple

Callable Types

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

Example

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

from typing import Callable

# Define a function that takes another function as an argument
def apply_operation(x: int, y: int, operation: Callable[[int, int], int]) -> int:
   return operation(x, y)

# Example functions to be passed as arguments
def add(a: int, b: int) -> int:
   return a + b

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

# Using the apply_operation function with different operations
result1 = apply_operation(5, 3, add)        # result1 will be 8
result2 = apply_operation(5, 3, multiply)   # result2 will be 15

print(result1)
print(result2)

执行以上代码,我们将获得以下 output -

8
15

Literal Types

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

Example

以下是示例 −

from typing import Literal

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

move("left")  # Valid
move("up")    # Valid

执行以上代码,我们将获得以下 output -

Moving left
Moving up

NewType

NewType 是 typing 模块中的一个函数,它允许我们根据现有类型创建不同的类型。通过区分同一基础类型的不同用途,这可以帮助为我们的代码添加类型安全。例如,我们可能希望区分用户 ID 和产品 ID,即使两者都表示为整数。

Example

以下是示例 −

from typing import NewType

# Create new types
UserId = NewType('UserId', int)
ProductId = NewType('ProductId', int)

# Define functions that use the new types
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}"

# Example usage
user_id = UserId(42)
product_id = ProductId(101)

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

执行以上代码,我们将获得以下 output -

User with ID 42
Product with ID 101