Menu

Type hint trong Python: chú thích kiểu cho hàm, list, dict

Type hint trong Python là gì, khi nào chúng hữu ích, và cú pháp để chú thích kiểu cho biến, chữ ký hàm, container và giá trị có thể là None.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Chú thích để mô tả, không để ép buộc

Type hint là một ghi chú bạn gắn vào một tên, thường là tham số hàm, nói rằng "cái này nên là int", "hàm này trả về một list chuỗi", v.v. Python không kiểm tra chúng lúc chạy. Truyền một chuỗi vào chỗ bạn chú thích là int cũng không gây lỗi. Trình soạn thảo và các công cụ bên ngoài (mypy, pyright, Pylance của VS Code dựa trên Pyright) đọc các type hint và cảnh báo bạn trước khi code chạy.

Trường hợp đơn giản nhất:

name: str chú thích kiểu cho tham số. -> str chú thích kiểu cho giá trị trả về. Cả hai lời gọi đều chạy. Lời gọi thứ hai là sai, một trình kiểm tra kiểu tĩnh sẽ đánh dấu nó, nhưng Python vẫn vui vẻ xử lý vì 42 tình cờ hỗ trợ việc chèn vào f"{...}".

Đó là mô hình tư duy then chốt: type hint là tài liệu mà máy đọc được. Chúng không thay đổi cách chương trình chạy.

Sao phải bận tâm?

Ba lợi ích cụ thể, theo thứ tự mức độ nhanh chóng mà chúng mang lại:

  1. Trình soạn thảo thông minh hơn. Tự động hoàn thành gợi ý đúng phương thức, đổi tên lan truyền chính xác, và rê chuột lên một biến sẽ cho biết kiểu của nó.
  2. Chữ ký hàm tự mô tả. def fetch(url: str, timeout: float = 5.0) -> dict: cho người đọc biết chính xác cần truyền vào gì và sẽ nhận lại gì, không cần đọc thân hàm.
  3. Trình kiểm tra kiểu bắt lỗi trước khi bạn chạy code. Chạy mypy . trên một dự án sẽ lộ ra những loại bug mà unit test thường bỏ sót: trả về None ở chỗ bạn mong đợi một giá trị, dùng dict ở chỗ đáng lẽ là list.

Với một script một tệp chỉ mình bạn dùng và chỉ cho hôm nay, cứ bỏ qua type hint. Với bất cứ thứ gì bạn sẽ quay lại hoặc chia sẻ, mười lăm giây để viết chúng sẽ được đền đáp trong vòng một giờ.

Các kiểu có sẵn cơ bản

Bạn không cần import gì cho những kiểu này:

Chú thích kiểu cho biến (name: str = "Rosa") hiếm khi cần thiết: Python suy ra kiểu từ vế phải. Hãy để dành chúng cho tham số, kiểu trả về và những lúc kiểu được suy ra còn mơ hồ.

Hàm không trả về gì thì dùng -> None:

List, dict, tuple và set

Container cần thêm một thông tin nữa: chúng chứa gì. Python hiện đại cho phép bạn dùng chỉ số trực tiếp trên các kiểu có sẵn:

Đọc thành lời:

  • list[float]: một list các số thực.
  • dict[str, int]: một dict có khóa là chuỗi và giá trị là int.
  • tuple[float, float]: một tuple gồm đúng hai số thực.
  • set[str]: một set các chuỗi.

Cú pháp list[...], dict[...] chạy từ Python 3.9 trở lên. Trong code cũ hơn bạn sẽ thấy List, Dict, Tuple được import từ typing: cùng ý nghĩa, cách viết cũ hơn.

Giá trị có thể là None

"Có thể là None" là trường hợp rất phổ biến. Nó có hai cách viết tương đương, cả hai đều ổn, nhưng cách mới dễ đọc hơn:

str | None nghĩa là "một chuỗi, hoặc None". Cú pháp | chạy từ Python 3.10 trở lên. Trong code cũ hơn bạn sẽ thấy Optional[str] từ module typing, mang cùng ý nghĩa.

Người gọi hàm thấy -> str | None sẽ biết phải kiểm tra None trước khi dùng kết quả: đó chính là mục đích của chú thích.

Union: cái này hoặc cái kia

Khi một giá trị có thể thuộc một trong vài kiểu, hãy dùng |:

Bạn có thể hợp nhiều hơn hai kiểu. int | str | float nghĩa là "bất kỳ kiểu nào trong ba kiểu này".

Chú thích kiểu cho biến bên trong hàm

Phần lớn thời gian Python tự tìm ra kiểu của biến cục bộ từ giá trị khởi tạo. Bạn chỉ cần chú thích khi:

  • Container bắt đầu rỗng và trình kiểm tra kiểu không đoán được nội dung của nó.
  • Giá trị có thể thuộc nhiều kiểu và bạn muốn chốt một kiểu.
  • Bạn muốn ghi lại ý đồ cho người đọc.

typing.Any là lối thoát hiểm: "Tôi không muốn chú thích chỗ này một cách chính xác." Hãy dùng nó có chừng mực. Lạm dụng Any khiến phần còn lại của type hint trở nên vô giá trị.

Chú thích kiểu cho lớp

Thuộc tính của lớp và chữ ký phương thức được chú thích giống như mọi hàm khác:

Dataclass thực sự bắt buộc phải có chú thích kiểu: decorator @dataclass đọc chúng để sinh ra __init__ và __repr__. Đó là nơi duy nhất chú thích kiểu có ảnh hưởng đến hành vi lúc chạy.

Tuple và trường hợp "độ dài bất kỳ"

tuple[...] có hai dạng hay khiến người mới bối rối:

  • tuple[float, float]: đúng hai số thực.
  • tuple[int, ...]: bao nhiêu int cũng được. Dấu ... (một thành phần cú pháp thật sự trong hệ thống kiểu) nghĩa là "và cứ thế tiếp tục".

Callable và bí danh kiểu

Khi một hàm nhận vào hoặc trả về một hàm khác, hãy dùng Callable:

Callable[[int], int] nghĩa là "một hàm nhận một int và trả về một int".

Khi một chú thích bị lặp đi lặp lại, hãy đặt tên cho nó:

Bí danh (alias) chỉ là một phép gán Python bình thường. Ở bất cứ đâu bạn dùng dạng dài, tên ngắn đều dùng được.

Chạy trình kiểm tra kiểu

Trình thông dịch Python bỏ qua type hint. Để thực sự kiểm tra chúng, hãy cài một trình kiểm tra kiểu. mypy là công cụ đầu tiên; pyright (được Pylance của VS Code dùng) thì nhanh hơn.

pip install mypy
mypy your_project/

Lần chạy đầu tiên sẽ lộ ra lỗi ở những chỗ bạn không ngờ tới. Hãy xử lý dần dần: # type: ignore tắt cảnh báo cho một dòng khi bạn cần đi tiếp.

Các IDE hiện đại chạy kiểm tra kiểu liên tục trong lúc bạn sửa code, nên phần lớn phản hồi đến trước cả khi bạn lưu.

Khi type hint không phù hợp

  • Script khám phá nhanh. Chú thích thêm phiền phức cho code chỉ sống được một giờ.
  • Code rất động. Siêu lập trình, hệ thống plugin và các mẫu tương tự thường vượt quá những gì hệ thống kiểu mô tả được. Hãy chú thích API bên ngoài và để phần bên trong lỏng hơn.
  • Thư viện bên thứ ba không có kiểu. Nếu một thư viện bạn import không có thông tin kiểu, Any sẽ lọt vào code của bạn. Không sao: đó không phải code bạn cần chú thích.

Với mọi trường hợp ở giữa, type hint là một thói quen nhỏ mang lại lợi ích lớn. Cái giá là vài phím gõ thêm cho mỗi chữ ký hàm. Đổi lại là ít bug hơn, tái cấu trúc dễ hơn và code tự giải thích chính nó.

Tiếp theo: module và import

Giờ bạn đã có đủ công cụ ở cấp độ hàm: đối số, decorator, type hint. Tiếp theo chúng ta sẽ xem Python tổ chức code qua nhiều tệp như thế nào: module, package và hệ thống import.

Câu hỏi thường gặp

Type hint trong Python là gì?

Type hint là các chú thích mô tả kiểu dữ liệu mong đợi của biến, tham số hàm và giá trị trả về. Bản thân Python không ép buộc chúng lúc chạy: chúng dành cho công cụ (IDE, linter, trình kiểm tra kiểu như mypy hoặc pyright) và cho người đọc code.

Type hint có làm Python chạy nhanh hơn không?

Không. Trình thông dịch Python bỏ qua type hint lúc chạy. Cái lợi nằm ở quá trình phát triển: trình soạn thảo bắt được nhiều lỗi gõ nhầm hơn, chữ ký hàm rõ ràng hơn, tái cấu trúc an toàn hơn.

Khi nào nên thêm type hint?

Thêm chúng vào chữ ký của các hàm công khai: tham số và kiểu trả về. Bên trong thân hàm thì thêm có chừng mực, chỉ ở chỗ kiểu của biến không hiển nhiên. Với script dùng một lần, chúng là tùy chọn. Với code dùng chung và thư viện, chúng nhanh chóng tỏ ra đáng công.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu