Python - Type Hints

Python type hints được giới thiệu trong PEP 484 để mang lại lợi ích của kiểu tĩnh cho một ngôn ngữ kiểu động. Mặc dù các gợi ý kiểu không thực thi kiểm tra kiểu tại thời gian chạy, chúng cung cấp một cách để chỉ định các kiểu mong đợi của variables , tham số hàm và giá trị trả về, có thể được kiểm tra bởi các công cụ phân tích tĩnh như mypy . Điều này nâng cao khả năng đọc mã, tạo điều kiện thuận lợi cho việc gỡ lỗi và cải thiện tính bảo trì tổng thể của mã.

Type hints trong Python sử dụng chú thích cho các tham số hàm, giá trị trả về và gán biến.

Python's type hints có thể được sử dụng để chỉ định nhiều loại khác nhau như data types cơ bản, bộ sưu tập, các loại phức tạp và các loại do người dùng định nghĩa. Mô-đun typing cung cấp nhiều loại tích hợp sẵn để đại diện cho các loại khác nhau này −

  • Basic Data Types
  • Collections Types
  • Optional Types
  • Union Types
  • Any Type
  • Type Aliases
  • Generic Types
  • Callable Types
  • Literal Types
  • NewType

Hãy xem từng cái một, lần lượt và chi tiết.

Basic Data Types

Trong Python, khi sử dụng type hints để chỉ định các kiểu cơ bản, chúng ta có thể đơn giản sử dụng tên của kiểu đó làm chú thích.

Example

Dưới đây là ví dụ về việc sử dụng các kiểu dữ liệu cơ bản như số nguyên, số thực, chuỗi, v.v. −

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

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

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

Collections Types

Trong Python, khi làm việc với các tập hợp như lists , tuples , dictionaries , v.v. trong type hints , chúng ta thường sử dụng mô-đun typing để chỉ định các loại tập hợp.

Example

Dưới đây là ví dụ về Collections được sử dụng trong 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))                                          

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được 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

Trong Python, Optional types được sử dụng để chỉ ra rằng một biến có thể thuộc một kiểu nhất định hoặc là None. Điều này đặc biệt hữu ích khi một hàm có thể không luôn trả về giá trị hoặc khi một tham số có thể chấp nhận một giá trị hoặc có thể để không xác định.

Example

Dưới đây là ví dụ về việc sử dụng optional types trong 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 will be 5.0
result2: Optional[float] = divide(10.0, 0.0)   # result2 will be None

print(result1)  
print(result2)                                           

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

5.0
None

Union Types

Python sử dụng kiểu Union để cho phép một biến chấp nhận các giá trị của các kiểu khác nhau. Điều này rất hữu ích khi một hàm hoặc cấu trúc dữ liệu có thể làm việc với nhiều loại đầu vào khác nhau hoặc sản xuất các loại đầu ra khác nhau.

Example

Dưới đây là ví dụ về điều này −

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)                                             

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

7.0710678118654755
None

Any Type

Trong Python, Any type là một kiểu gợi ý đặc biệt cho biết rằng một biến có thể thuộc bất kỳ kiểu nào. Nó về cơ bản vô hiệu hóa việc kiểm tra kiểu cho biến hoặc biểu thức đó. Điều này có thể hữu ích trong các tình huống mà kiểu của một giá trị không được biết trước hoặc khi làm việc với dữ liệu động.

Example

Sau đây là ví dụ về việc sử dụng loại Any trong 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'})                                           

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

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

Type Aliases

Type aliases trong Python được sử dụng để cung cấp các tên thay thế cho các kiểu đã tồn tại. Chúng có thể làm cho mã dễ đọc hơn bằng cách cung cấp các tên rõ ràng cho các chú thích kiểu phức tạp hoặc sự kết hợp của các kiểu. Điều này đặc biệt hữu ích khi làm việc với các cấu trúc lồng nhau hoặc các gợi ý kiểu dài.

Example

Dưới đây là ví dụ về việc sử dụng Type Aliases trong Type hints

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)                                             

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

[2, 5, 7, 10]
5.0

Generic Types

Generic types Tạo các hàm, lớp hoặc cấu trúc dữ liệu có thể xử lý bất kỳ loại nào trong khi vẫn duy trì tính an toàn kiểu. Các cấu trúc TypeVar và Generic trong mô-đun typing làm cho điều này trở nên khả thi. Chúng hữu ích cho việc tạo các thành phần tái sử dụng có thể hoạt động với các loại khác nhau mà không làm giảm kiểm tra kiểu.

Example

Dưới đây là ví dụ về nó −

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)                                              

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

1
apple

Callable Types

Kiểu Callable của Python được sử dụng để chỉ ra rằng một kiểu là một hàm hoặc một đối tượng có thể gọi được. Nó có trong mô-đun typing và cho phép bạn định nghĩa các kiểu của các tham số và kiểu trả về của một hàm. Điều này rất hữu ích cho các hàm bậc cao.

Example

Dưới đây là ví dụ về việc sử dụng kiểu Callable trong type hint

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)                                                

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

8
15

Literal Types

Loại Literal được sử dụng để chỉ định rằng một giá trị phải chính xác là một trong số các giá trị đã được định nghĩa trước.

Example

Dưới đây là ví dụ −

from typing import Literal

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

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

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

Moving left
Moving up

NewType

NewType là một hàm trong mô-đun typing cho phép chúng ta tạo ra các kiểu riêng biệt được kế thừa từ các kiểu hiện có. Điều này có thể hữu ích để thêm tính an toàn cho kiểu dữ liệu trong mã của chúng ta bằng cách phân biệt giữa các cách sử dụng khác nhau của cùng một kiểu dữ liệu cơ bản. Ví dụ, chúng ta có thể muốn phân biệt giữa ID người dùng và ID sản phẩm mặc dù cả hai đều được biểu diễn dưới dạng số nguyên.

Example

Dưới đây là ví dụ −

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                                   

Khi thực thi đoạn mã trên, chúng ta sẽ nhận được output

User with ID 42
Product with ID 101