Gợi ý loại Python Tùy chọn

Đây là phần thứ ba của loạt bài viết về hệ thống chú thích kiểu trong Python, viết tắt là type hints. Phần thứ hai thảo luận về một tập hợp các ví dụ dành cho người mới bắt đầu và nêu bật những lợi ích của việc sử dụng gợi ý loại

Loạt bài viết này nhằm vào những người mới nhập gợi ý và muốn giúp bạn bắt đầu

Trong phần thứ ba này, tôi sẽ tiếp tục thảo luận về các ví dụ nâng cao hơn một chút để hiểu sâu hơn về kiến ​​thức của bạn về gợi ý loại. Mỗi ví dụ sẽ đề cập đến một chủ đề nhất định và xem xét các gợi ý về loại từ một góc độ hơi khác. Hầu hết các ví dụ sẽ kết thúc bằng mẹo hoặc phương pháp hay nhất để giúp bạn cải thiện kỹ năng gợi ý loại của mình

Biến rỗng có ý nghĩa

Một biến có thể được khởi tạo dưới dạng một vùng chứa trống hoặc

countries: dict[str, tuple[str, int]] = {}
0 vì nội dung thực tế của nó được chỉ định sau trong mã. Ví dụ, đây có thể là trường hợp của biến giữ giá trị trả về của hàm. Thông thường, biến này được khởi tạo ngay ở phần đầu của thân hàm và giá trị của nó được gán nhiều lần trong toàn bộ mã. Khi giá trị trả về của hàm được chú thích kiểu chính xác, điều này sẽ không có vấn đề gì vì bạn đã biết kiểu của giá trị trả về nhờ gợi ý kiểu trong tiêu đề hàm (bạn có nhớ chú thích
countries: dict[str, tuple[str, int]] = {}
1 không?). Tuy nhiên, nếu kiểu trả về không được chú thích chính xác, bạn sẽ không biết chắc. Tương tự, nếu biến được đề cập không phải là giá trị trả về mà là một biến cục bộ nào đó không được ghi lại trong chuỗi tài liệu của hàm cũng như thông qua nhận xét nội tuyến, thì bạn khó có thể biết nó sẽ chứa gì. Giả sử bạn bắt gặp phép gán biến sau đây ở đâu đó trong đoạn mã

countries = {}

Tất cả những gì bạn biết về biến

countries: dict[str, tuple[str, int]] = {}
2 là nó là một từ điển vì nó được khởi tạo như vậy. Nhưng bạn không biết cấu trúc của từ điển này trông như thế nào. Mục đích dự định của biến này là gì? . Tuy nhiên, câu hỏi thú vị là mối quan hệ này trông như thế nào. Các khóa là gì và các giá trị là gì, từ điển này phức tạp đến mức nào?

Bây giờ, hãy để chúng tôi giúp người đọc bằng cách chú thích biến này

countries: dict[str, tuple[str, int]] = {}

Điều này có làm thay đổi hiểu biết của bạn về biến không? . Với gợi ý loại thích hợp, bạn biết chính xác những gì mong đợi từ từ điển này. Rằng các khóa của nó sẽ là các chuỗi (có thể là tên của các quốc gia) và các giá trị của nó sẽ là các bộ hai phần tử, phần tử đầu tiên là một chuỗi (có thể là thủ đô của quốc gia) và phần tử thứ hai là một số nguyên (có thể là dân số của quốc gia). Tất nhiên, bạn sẽ không biết các kiểu đại diện cho điều gì khi chỉ đọc các gợi ý về kiểu, nhưng bạn sẽ hiểu rõ hơn về cách từ điển này được cấu trúc và cách nó sẽ được sử dụng sau này trong mã. Và thực tế là các giá trị của nó là các bộ cho bạn biết điều gì đó về các giá trị. chúng được mong đợi là một cặp hai yếu tố cố định (bất biến), do đó, đó phải là dữ liệu hợp lệ cho tất cả các quốc gia (như thủ đô và dân số). Trong ví dụ này, gợi ý loại giúp giảm sự mơ hồ và không chắc chắn về cấu trúc và cách sử dụng biến

Đây là ví dụ đầu tiên mà chú thích kiểu được thực hiện cho một biến nằm ngoài định nghĩa hàm. Trên thực tế, bạn có thể gõ chú thích mọi thứ bằng Python, không chỉ các tham số chức năng. Tuy nhiên, khi bạn tương tác với các hàm hoặc phương thức thường xuyên hơn so với cách triển khai thực tế của chúng, gợi ý loại có giá trị nhất ở những nơi thường được truy cập

Tuy nhiên, hãy để tôi cung cấp cho bạn một số ví dụ khác về các chú thích loại biến bên ngoài các hàm có thể hữu ích

class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...

Ở đây, gợi ý loại rất hữu ích vì giá trị thực tế cho

countries: dict[str, tuple[str, int]] = {}
3 có thể được đặt muộn hơn nhiều, trong phương thức
countries: dict[str, tuple[str, int]] = {}
4 hoặc thậm chí muộn hơn. Trước gợi ý loại, chúng tôi thường đặt gợi ý loại trong nhận xét, nhưng vì các nhận xét bị bộ kiểm tra loại tĩnh bỏ qua và không được chuẩn hóa, tốt hơn hết là sử dụng gợi ý loại vì đó là mục đích của nó

Gợi ý loại thậm chí còn hữu ích hơn khi kết hợp với lớp dữ liệu

________số 8

Mặc dù Python không ngăn cản bạn khởi tạo một phiên bản

countries: dict[str, tuple[str, int]] = {}
5 với các loại sai, do đó,
countries: dict[str, tuple[str, int]] = {}
6 sẽ không gây ra lỗi, trình trang trí
countries: dict[str, tuple[str, int]] = {}
7 sẽ sử dụng thông tin gợi ý loại cho một số phép thuật bên trong như tự động tạo phương thức
countries: dict[str, tuple[str, int]] = {}
8 với chú thích loại phù hợp cho . Bạn thậm chí có thể sử dụng
countries: dict[str, tuple[str, int]] = {}
9 để diễn đạt rằng một biến là biến lớp thay vì biến thể hiện. Trong trường hợp này, một lần nữa, Python không ngăn bạn truy cập biến này thông qua một thể hiện (
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
0 thay vì
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
1) nhưng nó sẽ ngăn không cho biến lớp được thêm vào danh sách tham số của phương thức
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
2

countries: dict[str, tuple[str, int]] = {}
7

Bí danh loại có ý nghĩa

Đến bây giờ, bạn đã thấy khá nhiều gợi ý về loại và tôi phải thừa nhận rằng khả năng đọc không phải lúc nào cũng được cải thiện khi các loại trở nên phức tạp hơn và do đó, các gợi ý về loại dài hơn là cần thiết, nhất là với các loại lồng nhau và nhiều loại. Vì vậy, thay vì chấp nhận gợi ý loại dài hơn bao giờ hết, bạn có thể cải thiện cả khả năng đọc và ý nghĩa rất nhiều bằng cách giới thiệu tên loại của riêng bạn. Điều này là có thể bởi vì các chú thích kiểu chỉ là các đối tượng Python và có thể được gán cho các biến

Nhìn vào ví dụ sau

countries: dict[str, tuple[str, int]] = {}
8

Bằng cách giới thiệu các tên nói

class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
3,
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
4 và
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
5 như các loại mới, gợi ý loại không chỉ cung cấp thông tin về các tham số của chúng mà còn thông báo về miền và xây dựng một ngôn ngữ miền nhất quán. Bây giờ bạn có thể nghĩ về hàm
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
6 không còn là một hàm lấy hai danh sách số float và tạo ra một số duy nhất mà là một phép toán giữa hai vectơ tạo ra một số vô hướng. Và
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
7 của một vectơ lại là một đại lượng vô hướng, biểu thị độ dài của nó. Và bởi vì
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
8 của ma trận có hai phần tử nên ma trận phải là một đối tượng nào đó có hai chiều

Bằng cách gán các tên mới và có ý nghĩa cho các định nghĩa kiểu hiện có, bạn có thể tăng thêm khả năng đọc và hiểu mã của mình và truyền đạt ý định của bạn tới người đọc tốt hơn

Cập nhật cho Python 3. 10. Kể từ Python 3. 10 (và nhờ có PEP 613), có thể sử dụng 

class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
9 mới từ mô-đun 
from dataclasses import dataclass

@dataclass
class Point:
  x: int
  y: int
0 để khai báo rõ ràng một bí danh loại. Điều này giải quyết một số vấn đề với cú pháp cũ, nói đúng ra, là một biểu thức toàn cục và chỉ được hiểu là bí danh kiểu nếu được sử dụng đúng cách. Với 
class MyClass:
    # You can optionally declare instance variables in the class body
    attr: int
    ...
9 , bạn có thể viết lại ví dụ thành

countries = {}
8

Điều này yêu cầu nhập bổ sung, điều này có thể giống như một gánh nặng, nhưng nó làm tăng khả năng đọc, nêu rõ ý định của bạn và cải thiện khả năng của trình kiểm tra kiểu tĩnh

Tránh nhầm lẫn về nhiều loại

Nếu bạn cần cho phép nhiều loại, bạn có thể sử dụng

from dataclasses import dataclass

@dataclass
class Point:
  x: int
  y: int
2, e. g.
from dataclasses import dataclass

@dataclass
class Point:
  x: int
  y: int
3 cho người đọc biết rằng một biến có thể là một chuỗi hoặc một số nguyên. Điều này có thể hữu ích bất cứ khi nào không thể yêu cầu một loại hoặc bạn muốn cung cấp một số tiện lợi cho người dùng chức năng hoặc lớp của bạn. Tuy nhiên, tốt nhất là tránh nhiều loại để rõ ràng và sử dụng cơ chế khác như công văn đơn lẻ hoặc loại biến tổng quát hơn như từ điển

Nhìn vào ví dụ sau

countries: dict[str, tuple[str, int]] = {}
1

Có vẻ như các tác giả của hàm

from dataclasses import dataclass

@dataclass
class Point:
  x: int
  y: int
4 muốn ít nghiêm ngặt hơn về loại tham số
from dataclasses import dataclass

@dataclass
class Point:
  x: int
  y: int
5. Thay vì luôn yêu cầu nó phải là một danh sách, họ cũng thấy trước khả năng hoặc sự cần thiết phải cho phép một chuỗi đơn. Ta có thể hiểu ngay kiểu hint này như sau. Khi chỉ có một địa chỉ duy nhất bạn muốn gửi email đến, bạn có thể chuyển địa chỉ này cho chức năng, nhưng nếu bạn có nhiều địa chỉ, bạn cũng có thể chuyển toàn bộ danh sách và chức năng sẽ xử lý nó. Thật tuyệt khi thông tin này được mã hóa trực tiếp trong một gợi ý loại, phải không?

Nếu bạn thắc mắc trình soạn thảo yêu thích của mình xử lý trường hợp có nhiều loại như thế nào, thì ít nhất là đối với VSC, tôi có thể nói với bạn rằng nó rất thông minh và gợi ý tất cả các phương thức cho cả chuỗi và danh sách. Không phải những gì tôi đã mong đợi nhưng chắc chắn đánh giá cao

Tránh nhầm lẫn về Không

countries: dict[str, tuple[str, int]] = {}
0 là một trong những người bạn tốt nhất của chúng tôi và đồng thời có thể thực sự khó chịu. Cách tốt nhất là khởi tạo các tham số tùy chọn với giá trị mặc định là
countries: dict[str, tuple[str, int]] = {}
0 để bạn có thể đối chiếu với
countries: dict[str, tuple[str, int]] = {}
0 trước khi sử dụng thuộc tính và tránh sự cố về một số lỗi khó chịu, e. g. khi sử dụng danh sách trống làm mặc định (xem [7]). Tuy nhiên, điều này không ngăn người dùng chức năng của bạn chuyển
countries: dict[str, tuple[str, int]] = {}
0 tới bất kỳ tham số nào, ngay cả những tham số bắt buộc. Điều này xảy ra thường xuyên, chủ yếu là khi xâu chuỗi các hàm và chuyển qua các giá trị trả về. Vậy bạn có thể làm gì để nhận ra điều này?

Hãy trở lại với ví dụ về việc gửi email, lần này một chút chi tiết

countries: dict[str, tuple[str, int]] = {}
0

Có một số tham số có gợi ý loại

countries: dict[str, tuple[str, int]] = {}
72, cụ thể là
countries: dict[str, tuple[str, int]] = {}
73,
countries: dict[str, tuple[str, int]] = {}
74 và
countries: dict[str, tuple[str, int]] = {}
75. Hoàn toàn không có gợi ý loại, kiểm tra loại tĩnh sẽ không gây ra bất kỳ lỗi nào cho bạn khi chuyển
countries: dict[str, tuple[str, int]] = {}
0 cho bất kỳ tham số nào, vì theo mặc định, tham số không có gợi ý loại có loại
countries: dict[str, tuple[str, int]] = {}
77, cũng được đáp ứng bởi
countries: dict[str, tuple[str, int]] = {}
0. Khi thêm một gợi ý loại mà không có
countries: dict[str, tuple[str, int]] = {}
72, thì
countries: dict[str, tuple[str, int]] = {}
0 không còn là một tùy chọn hợp lệ và trình kiểm tra loại của bạn sẽ thông báo cho bạn về loại không tương thích. Vì vậy, ví dụ khi chuyển
countries: dict[str, tuple[str, int]] = {}
0 làm giá trị cho
countries: dict[str, tuple[str, int]] = {}
82, bạn nhận được.
countries: dict[str, tuple[str, int]] = {}
83

Để cho phép rõ ràng đối với

countries: dict[str, tuple[str, int]] = {}
0, bạn có thể thêm
countries: dict[str, tuple[str, int]] = {}
72 vào gợi ý loại, cho phép cả loại thực tế và giá trị đặc biệt
countries: dict[str, tuple[str, int]] = {}
0. Bây giờ, việc gọi hàm với
countries: dict[str, tuple[str, int]] = {}
0 cho tham số
countries: dict[str, tuple[str, int]] = {}
75 không còn là vấn đề nữa vì
countries: dict[str, tuple[str, int]] = {}
89 là lối tắt của
countries = {}
80 và do đó cho phép giá trị
countries: dict[str, tuple[str, int]] = {}
0

Một ví dụ hơi khác là như sau. Hãy tưởng tượng bạn muốn gọi hàm

countries = {}
82 với một số danh sách số. Tuy nhiên, một số số thực sự có thể là giá trị
countries: dict[str, tuple[str, int]] = {}
0 do một số lỗi trong quá trình ghi (e. g. giá trị cảm biến). Đây là một vấn đề vì hàm
countries = {}
82 không xử lý tốt các giá trị
countries: dict[str, tuple[str, int]] = {}
0 và thay vào đó ném ra một giá trị
countries = {}
86

countries: dict[str, tuple[str, int]] = {}
6

Điều này khó thấy nếu không có trình kiểm tra kiểu tĩnh. Tuy nhiên, nếu có một biến

countries = {}
87 được chú thích chính xác bằng
countries = {}
88, cho biết rằng một số số có thể bị thiếu, Pylance sẽ thông báo cho bạn về sự cố khi chuyển biến này cho hàm
countries = {}
82. “Không có tình trạng quá tải nào đối với
countries = {}
82 khớp với các đối số được cung cấp Các loại đối số.
countries: dict[str, tuple[str, int]] = {}
11

Gợi ý loại Python Tùy chọn

Vì vậy, nhập gợi ý đã ngăn bạn thành công khỏi lỗi thời gian chạy do giá trị

countries: dict[str, tuple[str, int]] = {}
0 ẩn trong một số thuộc tính

Điều này kết thúc phần thứ ba của loạt bài này. Bạn nên tìm hiểu về cách chú thích các biến chưa được khởi tạo đầy đủ, các biến thể hiện và lớp và cách xử lý nhiều loại cùng một lúc cũng như giá trị đặc biệt

countries: dict[str, tuple[str, int]] = {}
0. Tôi nghĩ đây là đủ ví dụ, vì vậy phần tiếp theo của loạt bài này sẽ giải quyết cách thực sự kiểm tra gợi ý loại


Tôi hy vọng bạn đã thích đọc bài viết. Nếu bạn có bất kỳ câu hỏi, nhận xét hoặc đề xuất nào, vui lòng liên hệ với tôi qua PyBites Slack, LinkedIn hoặc GitHub. Bạn cũng có thể để lại bình luận của mình ngay trên trang này

Hãy cho tôi biết nếu bạn muốn đọc thêm về chủ đề này hoặc bất kỳ chủ đề nào khác, về vấn đề đó

Tài nguyên

Tài nguyên bao gồm toàn bộ loạt bài viết về gợi ý loại. Không phải tất cả các tài nguyên đều được tham chiếu trong phần này

Python gợi ý loại tùy chọn là gì?

Python có hỗ trợ cho "gợi ý loại" tùy chọn. Những "gợi ý kiểu" này là một cú pháp đặc biệt cho phép khai báo kiểu của một biến . Bằng cách khai báo các loại cho biến của bạn, trình chỉnh sửa và công cụ có thể hỗ trợ bạn tốt hơn.

Các gợi ý loại Python có được thực thi không?

Gợi ý loại được thực hiện bằng chú thích Python (được giới thiệu từ PEP 3107). Chúng được sử dụng để thêm kiểu cho biến, tham số, đối số hàm cũng như giá trị trả về, thuộc tính lớp và phương thức của chúng. Thêm gợi ý loại không có hiệu ứng thời gian chạy. đây chỉ là những gợi ý và không tự thực thi .

Liệu Python 3. 6 gợi ý loại hỗ trợ?

Bạn có thể thêm gợi ý loại cho tham số hàm/phương thức và loại trả về (Python 3. 5) và các biến được sử dụng trong phép gán (khai báo hiệu quả – Python 3. 6).

Việc sử dụng gợi ý kiểu trong Python là gì?

Python là một ngôn ngữ được nhập động, có nghĩa là bạn không bao giờ phải chỉ ra rõ ràng đó là loại biến nào . Nhưng trong một số trường hợp, gõ động có thể dẫn đến một số lỗi rất khó gỡ lỗi và trong những trường hợp đó, Gợi ý nhập hoặc Nhập tĩnh có thể thuận tiện.