- Giới thiệu 14 tính năng nâng cao trong Python ít được biết đến, kèm theo ví dụ thực tế
- Cung cấp phần giải thích chuyên sâu về typing tĩnh và thiết kế cấu trúc như
typing, generics, protocols, context managers
- Cũng bao gồm structural pattern matching mới được giới thiệu từ Python 3.10 trở lên, cùng các kỹ thuật tối ưu hiệu năng như slots và metaclass
- Bao gồm các mẹo để viết mã gọn gàng hơn như
f-string, cache, future, proxy, for-else, walrus
- Mỗi tính năng đều có liên kết và tài liệu tham khảo để học thêm, với cách trình bày dễ tiếp cận ngay cả với lập trình viên junior
Tóm tắt 14 tính năng Python nâng cao
# Overload kiểu dữ liệu
- Decorator
@overload cho phép định nghĩa nhiều type signature cho một hàm
- Trình kiểm tra kiểu có thể suy luận chính xác kiểu trả về theo giá trị đối số được truyền vào
- Có thể dùng
Literal để giới hạn giá trị chuỗi
- Cũng có thể triển khai function signature chỉ yêu cầu một trong hai giá trị
id hoặc username
- Có thể dùng
Literal như một phương án thay thế Enum nhẹ hơn để đảm bảo an toàn kiểu
# Đối số chỉ nhận theo từ khóa / chỉ nhận theo vị trí
- Dùng
* để đặt đối số chỉ nhận theo từ khóa (không thể dùng đối số vị trí)
- Dùng
/ để đặt đối số chỉ nhận theo vị trí (không thể dùng đối số từ khóa)
- Khi thiết kế API, có thể ép buộc rõ ràng cách sử dụng đối số
# Future annotations (__future__)
- Type hint vốn được đánh giá ngay tại runtime nên có thể phát sinh vấn đề về thứ tự khai báo
- Có thể trì hoãn thời điểm đánh giá bằng
from __future__ import annotations
- Tuy nhiên, vì hoạt động theo cách xử lý chuỗi nên cần cẩn thận khi dùng kiểu ở runtime
PEP 649 đề xuất cải tiến bằng cơ chế đánh giá trì hoãn cho thuộc tính __annotations__
# Cú pháp Generic
- Từ Python 3.12, Python hỗ trợ cú pháp định nghĩa generic kiểu mới
- Thay vì
TypeVar, có thể dùng trực quan hơn với dạng class Foo[T, U: int]
- Variadic Generics cũng được đưa vào, cho phép xử lý nhiều kiểu đa dạng
- Cách định nghĩa type alias cũng gọn hơn, có thể dùng dạng
type Vector = list[float]
# Protocols
- Đây là phiên bản kiểm tra kiểu của Duck Typing, cho phép triển khai structural subtyping
- Nếu một class có các method nhất định thì vẫn có thể tương thích kiểu mà không cần kế thừa kiểu
- Có thể mở rộng để dùng với kiểm tra
isinstance bằng @runtime_checkable
# Context Manager
- Là đối tượng có các method
__enter__, __exit__, được dùng trong khối with
- Có thể triển khai đơn giản theo kiểu hàm bằng decorator
contextlib.contextmanager
- Có thể thực hiện thiết lập và dọn dẹp trước và sau
yield
# Structural Pattern Matching
- Cú pháp
match-case giúp rẽ nhánh trực quan cho các cấu trúc dữ liệu phức tạp
- Hỗ trợ destructuring tuple/list, OR pattern, điều kiện guard (
if), và wildcard
- Vì có thể rẽ nhánh dựa trên cấu trúc dữ liệu nên cải thiện khả năng đọc và bảo trì
# Tối ưu hóa __slots__
- Dùng các slot cố định thay cho
__dict__ để tối ưu bộ nhớ và tốc độ
__slots__ sử dụng một tuple chỉ định tên thuộc tính
- Ngăn việc thêm các thuộc tính không cần thiết vào class
- Tuy nhiên đây chỉ là mức tối ưu vi mô nên cần cân nhắc khi sử dụng
# Tổng hợp mẹo code style Python
- Cú pháp for-else:
else sẽ chạy nếu vòng lặp kết thúc mà không có break
- Toán tử walrus (
:=): cho phép vừa gán biến vừa kiểm tra
- Short-circuit với
or: trả về giá trị đầu tiên là đúng trong nhiều giá trị
- Chaining toán tử so sánh: có thể viết gọn như
0 < x < 10
# Định dạng nâng cao với f-string
- Có thể dùng cú pháp
f"{변수=}" để biểu diễn phục vụ debug
- Hỗ trợ nhiều tùy chọn như định dạng số (
:.2f, :+.2f, :,), định dạng ngày (%Y-%m-%d)
- Có thể tận dụng mini-language định dạng cho căn giữa, padding, biểu diễn phần trăm
# Decorator cache
@lru_cache và @cache giúp lưu kết quả hàm để cải thiện tốc độ
- Hữu ích với các hàm đệ quy hoặc các phép tính lặp lại nhiều lần
@cache được giới thiệu từ Python 3.9, cung cấp cache mặc định không giới hạn
# Future trong Python
- Là đối tượng xử lý bất đồng bộ tương tự Promise trong JS
- Có thể quản lý kết quả bất đồng bộ bằng
Future.set_result(), add_done_callback()
asyncio.Future() có thể dùng cùng await
- Khi dùng với
ThreadPoolExecutor, cũng có thể xử lý song song nền
# Thuộc tính proxy (Proxy Property)
- Cho phép một thuộc tính của class vừa hoạt động như thuộc tính, vừa như hàm
- Cung cấp hai chức năng này thông qua
__get__, __call__, __repr__
- Khi thiết kế API, có thể xử lý giá trị mặc định và lời gọi có tham số theo một cách thống nhất
- Dù ít dùng trong thực tế, đây vẫn là một ví dụ thử nghiệm đáng tham khảo
# Metaclass
- Là class của class, dùng để tạo ra chính các class
- Có thể triển khai logic meta như thao tác thuộc tính class hoặc tự động đăng ký
- Trên thực tế, phần lớn trường hợp có thể thay bằng decorator
- Trong Django, SQLAlchemy, Pydantic... metaclass vẫn được dùng nội bộ
5 bình luận
Từ góc nhìn backend, tôi từng có trải nghiệm rằng metaclass khiến việc gỡ lỗi trở nên khó khăn hơn.
Xin lưu ý rằng
for-elsethường bị xem là anti-pattern vì có ý kiến cho rằng nó không có tính dễ đọc hay rõ ràng cao, vàasyncio.Futuređược coi là chi tiết triển khai nội bộ củaasyncio.Cảm ơn. Đặc biệt là mục số 10, tôi sẽ áp dụng ngay.
Thêm quy tắc code AI..
Cảm ơn vì mẹo hay.
Ý kiến trên Hacker News
Xin chào! Tôi là tác giả gốc của bài blog này! Tôi đã rất ngạc nhiên khi thấy bài viết của mình lên trang nhất HN lúc 4 giờ sáng
Mỗi khi dùng Python, tôi lại lo rằng đoạn mã của mình sẽ trông như đang dùng Python sai cách
Python nên vẫn là Python, còn golang, Rust, Typescript thì mỗi ngôn ngữ nên giữ triết lý và thiết kế riêng của mình
Điểm mạnh lớn nhất của Python là nó tạo cảm giác như mã giả có thể chạy được
Góp ý về mục 9.3, phần evaluation: nếu có chuỗi rỗng thì việc đánh giá sẽ diễn ra khác đi
Là người chuyển từ Javascript/Typescript sang Python, tôi thấy đây là một tài nguyên hữu ích
Phần lớn các tính năng này không phải là tính năng nâng cao
Điều tôi muốn thay đổi trong danh sách là việc đưa các container của collections.abc vào
Tôi rất thích đọc bài này