Gõ python có thể gọi được là gì?

Vấn đề chính với gợi ý loại có thể gọi được là chúng có thể gây hiểu lầm. Ví dụ: đoạn mã sau sử dụng gợi ý loại có thể gọi được để chỉ ra rằng hàm f[] phải được coi là hàm nhận một đối số

chắc chắn f[x]

print[“Trong f[] x là {}”. định dạng[x]]

Tuy nhiên, đoạn mã này thực sự định nghĩa một hàm nhận hai đối số. Nếu bạn cố chạy mã này, bạn sẽ nhận được thông báo lỗi như thế này

Trong f[] x không được xác định

Thông báo lỗi này là do Python không biết cách diễn giải gợi ý kiểu có thể gọi được trong ngữ cảnh này. Nói chung, các gợi ý kiểu có thể gọi được chỉ hữu ích nếu bạn thực sự đang xác định một hàm nhận một hoặc nhiều đối số

def foo[x: callable[[int], int]] -> int:
    return x[3]
    
    
#In this example, the foo function takes an argument x that must be a callable object, 
#and returns an int. The callable object must take an int as its first argument 
#and return an int.

#Khi hàm foo được gọi, nó sẽ gọi hàm x với đối số đầu tiên là 3.
#Giá trị trả về của hàm x sẽ được trả về bởi hàm foo.

nội dung

  • 1 Gợi ý nhập
  • 2 Nhập liệu là gì

Nhập gợi ý

Gợi ý kiểu là một tính năng của ngôn ngữ lập trình Python cho phép bạn chỉ ra cho trình biên dịch biết loại biến hoặc hàm mà bạn đang đề cập đến

Trong hướng dẫn này, bạn sẽ tìm hiểu về kiểm tra kiểu Python. Theo truyền thống, các kiểu đã được xử lý bởi trình thông dịch Python một cách linh hoạt nhưng ngầm định. Các phiên bản Python gần đây cho phép bạn chỉ định các gợi ý loại rõ ràng mà các công cụ khác nhau có thể sử dụng để giúp bạn phát triển mã của mình hiệu quả hơn

Trong hướng dẫn này, bạn sẽ tìm hiểu về những điều sau đây

  • Nhập chú thích và nhập gợi ý
  • Thêm các loại tĩnh vào mã, cả mã của bạn và mã của người khác
  • Chạy trình kiểm tra kiểu tĩnh
  • Thực thi các loại trong thời gian chạy

Đây là một hướng dẫn toàn diện sẽ bao gồm rất nhiều nền tảng. Nếu bạn muốn xem nhanh cách gợi ý kiểu hoạt động trong Python và xem liệu kiểm tra kiểu có phải là thứ bạn sẽ đưa vào mã của mình hay không, bạn không cần phải đọc tất cả. Hai phần Xin chào các loại và Ưu và nhược điểm sẽ cho bạn biết cách hoạt động của kiểm tra loại và các đề xuất về thời điểm nó sẽ hữu ích

Tiền thưởng miễn phí. 5 Suy nghĩ về Làm chủ Python, một khóa học miễn phí dành cho các nhà phát triển Python cho bạn thấy lộ trình và tư duy mà bạn sẽ cần để đưa các kỹ năng Python của mình lên một tầm cao mới

Loại hệ thống

Tất cả các ngôn ngữ lập trình bao gồm một số loại hệ thống loại chính thức hóa các loại đối tượng mà nó có thể làm việc và cách các loại đó được xử lý. Chẳng hạn, một hệ thống loại có thể định nghĩa một loại số, với

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

09 là một ví dụ về đối tượng thuộc loại số

Loại bỏ các quảng cáo

Nhập động

Python là một ngôn ngữ được gõ động. Điều này có nghĩa là trình thông dịch Python chỉ kiểm tra kiểu khi mã chạy và kiểu của một biến được phép thay đổi trong suốt thời gian tồn tại của nó. Các ví dụ giả sau đây chứng minh rằng Python có kiểu gõ động

>>>

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'

Trong ví dụ đầu tiên, nhánh

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

10 không bao giờ chạy nên nó không bao giờ được kiểm tra loại. Ví dụ thứ hai cho thấy rằng khi đánh giá
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

10, nó sẽ tăng giá trị
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

12 vì bạn không thể thêm một số nguyên và một chuỗi trong Python

Tiếp theo, hãy xem liệu các biến có thể thay đổi loại không

>>>

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

13 trả về loại đối tượng. Những ví dụ này xác nhận rằng loại
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

14 được phép thay đổi và Python suy ra chính xác loại khi nó thay đổi

Nhập tĩnh

Ngược lại với gõ động là gõ tĩnh. Kiểm tra loại tĩnh được thực hiện mà không cần chạy chương trình. Trong hầu hết các ngôn ngữ được nhập tĩnh, chẳng hạn như C và Java, điều này được thực hiện khi chương trình của bạn được biên dịch

Với kiểu gõ tĩnh, các biến thường không được phép thay đổi loại, mặc dù có thể tồn tại các cơ chế chuyển một biến sang một loại khác

Hãy xem một ví dụ nhanh từ một ngôn ngữ được gõ tĩnh. Hãy xem xét đoạn mã Java sau

String thing;
thing = "Hello";

Dòng đầu tiên tuyên bố rằng tên biến

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

14 được liên kết với loại
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

16 tại thời điểm biên dịch. Tên không bao giờ có thể được phục hồi thành loại khác. Ở dòng thứ hai,
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

14 được gán giá trị. Nó không bao giờ có thể được gán một giá trị không phải là đối tượng
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

16. Chẳng hạn, nếu sau này bạn nói
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

19, trình biên dịch sẽ báo lỗi do các kiểu không tương thích

Python sẽ luôn là một ngôn ngữ được gõ động. Tuy nhiên, PEP 484 đã giới thiệu các gợi ý về kiểu, cho phép thực hiện kiểm tra kiểu tĩnh của mã Python

Không giống như cách các loại hoạt động trong hầu hết các ngôn ngữ được nhập tĩnh khác, bản thân các gợi ý nhập không khiến Python thực thi các loại. Đúng như tên gọi, gợi ý nhập chỉ đề xuất các loại. Có những công cụ khác mà bạn sẽ thấy sau, thực hiện kiểm tra kiểu tĩnh bằng gợi ý kiểu

gõ vịt

Một thuật ngữ khác thường được sử dụng khi nói về Python là duck typing. Biệt danh này xuất phát từ câu "nếu nó đi như vịt và kêu quạc quạc như vịt, thì nó phải là vịt" [hoặc bất kỳ biến thể nào của nó]

Gõ vịt là một khái niệm liên quan đến gõ động, trong đó loại hoặc lớp của một đối tượng ít quan trọng hơn các phương thức mà nó định nghĩa. Sử dụng cách gõ vịt bạn hoàn toàn không kiểm tra các loại. Thay vào đó, bạn kiểm tra sự hiện diện của một phương thức hoặc thuộc tính nhất định

Ví dụ, bạn có thể gọi

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20 trên bất kỳ đối tượng Python nào xác định phương thức
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

21

>>>

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

7

Lưu ý rằng cuộc gọi đến _____120 cho giá trị trả về của phương thức _______121. Trên thực tế, việc triển khai

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20 về cơ bản tương đương như sau

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
1

Để gọi

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

25, ràng buộc thực sự duy nhất đối với
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

26 là nó phải xác định một phương thức
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

21. Mặt khác, đối tượng có thể thuộc các loại khác nhau như ________ 128, ________ 129, ________ 130 hoặc ________ 131

Kiểu gõ vịt được hỗ trợ phần nào khi thực hiện kiểm tra kiểu tĩnh của mã Python, sử dụng kiểu con cấu trúc. Bạn sẽ tìm hiểu thêm về cách gõ vịt sau

Loại bỏ các quảng cáo

xin chào các loại

Trong phần này, bạn sẽ thấy cách thêm gợi ý loại vào một hàm. Hàm sau biến một chuỗi văn bản thành một dòng tiêu đề bằng cách thêm cách viết hoa thích hợp và một dòng trang trí

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
9

Theo mặc định, hàm trả về dòng tiêu đề được căn trái với phần gạch chân. Bằng cách đặt cờ

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32 thành
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

33, bạn có thể đặt dòng tiêu đề ở giữa với đường bao quanh là
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

34

>>>

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

3

Đã đến lúc cho gợi ý loại đầu tiên của chúng tôi. Để thêm thông tin về các kiểu vào hàm, bạn chỉ cần chú thích các đối số của nó và trả về giá trị như sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

4

Cú pháp

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

35 nói rằng đối số
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

36 phải thuộc loại
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28. Tương tự, đối số tùy chọn
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32 phải có loại
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 với giá trị mặc định là
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

40. Cuối cùng, ký hiệu
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

41 xác định rằng
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

42 sẽ trả về một chuỗi

Về phong cách, PEP 8 khuyến nghị như sau

  • Sử dụng các quy tắc bình thường cho dấu hai chấm, nghĩa là không có dấu cách trước và một dấu cách sau dấu hai chấm.
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    35
  • Sử dụng khoảng trắng xung quanh dấu
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    44 khi kết hợp chú thích đối số với giá trị mặc định.
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    45
  • Sử dụng khoảng trắng xung quanh mũi tên
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    46.
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    47

Thêm gợi ý loại như thế này không có hiệu ứng thời gian chạy. chúng chỉ là gợi ý và không được thực thi trên chính chúng. Chẳng hạn, nếu chúng ta sử dụng sai loại đối số [được thừa nhận là có tên xấu]

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32, thì mã vẫn chạy mà không có bất kỳ sự cố hoặc cảnh báo nào

>>>

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

9

Ghi chú. Lý do điều này có vẻ hiệu quả là chuỗi

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

49 được so sánh là trung thực. Sử dụng
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

50 sẽ không có tác dụng như mong muốn vì
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

51 cũng đúng

Để bắt loại lỗi này, bạn có thể sử dụng trình kiểm tra kiểu tĩnh. Nghĩa là, một công cụ kiểm tra các loại mã của bạn mà không thực sự chạy nó theo nghĩa truyền thống

Bạn có thể đã có một trình kiểm tra loại như vậy được tích hợp sẵn trong trình soạn thảo của mình. Chẳng hạn, PyCharm ngay lập tức đưa ra cảnh báo cho bạn

Tuy nhiên, công cụ phổ biến nhất để thực hiện kiểm tra kiểu là Mypy. Bạn sẽ nhận được phần giới thiệu ngắn về Mypy trong giây lát, trong khi bạn có thể tìm hiểu thêm về cách thức hoạt động của nó sau này

Nếu bạn chưa có Mypy trên hệ thống của mình, bạn có thể cài đặt nó bằng cách sử dụng

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

52

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

4

Đặt đoạn mã sau vào tệp có tên

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

53

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

0

Đây thực chất là mã giống như bạn đã thấy trước đó. định nghĩa của

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

42 và hai ví dụ đang sử dụng nó

Bây giờ hãy chạy Mypy trên mã này

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

1

Dựa trên các gợi ý về loại, Mypy có thể cho chúng tôi biết rằng chúng tôi đang sử dụng loại sai trên dòng 10

Để khắc phục sự cố trong mã, bạn nên thay đổi giá trị của đối số

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32 mà bạn đang chuyển vào. Bạn cũng có thể đổi tên cờ
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32 thành tên nào đó ít khó hiểu hơn

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

2

Ở đây bạn đã thay đổi

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32 thành
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

58 và sử dụng đúng giá trị Boolean cho
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

58 khi gọi
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

42. Mã bây giờ vượt qua Mypy

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

3

Thông báo thành công xác nhận không có lỗi loại nào được phát hiện. Các phiên bản Mypy cũ hơn được sử dụng để chỉ ra điều này bằng cách không hiển thị đầu ra nào cả. Hơn nữa, khi bạn chạy mã, bạn sẽ thấy đầu ra dự kiến

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

4

Dòng tiêu đề đầu tiên được căn sang trái, trong khi dòng thứ hai được căn giữa

Loại bỏ các quảng cáo

Ưu và nhược điểm

Phần trước đã cho bạn biết một chút về việc kiểm tra kiểu trong Python trông như thế nào. Bạn cũng đã thấy một ví dụ về một trong những ưu điểm của việc thêm các loại vào mã của bạn. gõ gợi ý giúp bắt lỗi nhất định. lợi thế khác bao gồm

  • Nhập gợi ý giúp ghi lại mã của bạn. Theo truyền thống, bạn sẽ sử dụng chuỗi tài liệu nếu bạn muốn ghi lại các loại đối số của hàm được mong đợi. Điều này hoạt động, nhưng vì không có tiêu chuẩn cho chuỗi tài liệu [mặc dù PEP 257, chúng không thể dễ dàng sử dụng để kiểm tra tự động

  • Nhập gợi ý cải thiện IDE và linters. Chúng làm cho việc lập luận tĩnh về mã của bạn trở nên dễ dàng hơn nhiều. Điều này đến lượt nó cho phép các IDE cung cấp khả năng hoàn thành mã tốt hơn và các tính năng tương tự. Với chú thích loại, PyCharm biết rằng

    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    36 là một chuỗi và có thể đưa ra các đề xuất cụ thể dựa trên điều này

  • Nhập gợi ý giúp bạn xây dựng và duy trì kiến ​​trúc sạch hơn. Hành động viết các gợi ý về loại buộc bạn phải suy nghĩ về các loại trong chương trình của mình. Mặc dù bản chất động của Python là một trong những tài sản tuyệt vời của nó, nhưng ý thức về việc dựa vào kiểu gõ vịt, phương thức quá tải hoặc nhiều loại trả về là một điều tốt

Tất nhiên, kiểm tra kiểu tĩnh không phải là toàn đào và kem. Ngoài ra còn có một số nhược điểm bạn nên xem xét

  • Nhập gợi ý khiến nhà phát triển mất thời gian và công sức để thêm. Mặc dù nó có thể được đền đáp bằng việc dành ít thời gian hơn để gỡ lỗi, nhưng bạn sẽ dành nhiều thời gian hơn để nhập mã

  • Nhập gợi ý hoạt động tốt nhất trong Pythons hiện đại. Chú thích đã được giới thiệu trong Python 3. 0 và có thể sử dụng nhận xét loại trong Python 2. 7. Tuy nhiên, những cải tiến như chú thích biến và hoãn đánh giá gợi ý loại có nghĩa là bạn sẽ có trải nghiệm tốt hơn khi thực hiện kiểm tra loại bằng Python 3. 6 hoặc thậm chí Python 3. 7

  • Gõ gợi ý giới thiệu một hình phạt nhẹ trong thời gian khởi động. Nếu bạn cần sử dụng mô-đun

    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    62, thời gian nhập có thể là đáng kể, đặc biệt là trong các tập lệnh ngắn

Đo thời gian nhậpHiển thị/Ẩn

Sau này, bạn sẽ tìm hiểu về mô-đun

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 và mức độ cần thiết của mô-đun này trong hầu hết các trường hợp khi bạn thêm gợi ý loại. Nhập mô-đun nhất thiết phải mất một thời gian, nhưng bao nhiêu?

Để có một số ý tưởng về điều này, hãy tạo hai tệp.

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

64 phải là một tệp trống, trong khi
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

65 phải chứa dòng sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

5

Trên Linux, khá dễ dàng để kiểm tra xem quá trình nhập

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 mất bao nhiêu thời gian bằng cách sử dụng tiện ích
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

67

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

6

Vì vậy, việc chạy tập lệnh

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

68 mất khoảng 45 mili giây. Tất nhiên đây không phải là toàn bộ thời gian dành cho việc nhập khẩu
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62. Một số trong số này là chi phí khởi động trình thông dịch Python, vì vậy hãy so sánh với việc chạy Python trên một tệp trống

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

7

Dựa trên thử nghiệm này, quá trình nhập mô-đun

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 mất khoảng 17 mili giây trên Python 3. 6

Một trong những cải tiến được quảng cáo trong Python 3. 7 khởi động nhanh hơn. Hãy xem nếu kết quả là khác nhau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

8

Thật vậy, thời gian khởi động chung giảm khoảng 8 mili giây và thời gian nhập

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 giảm từ 17 xuống còn khoảng 6 mili giây—nhanh hơn gần 3 lần

Sử dụng

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72

Có các công cụ tương tự trên các nền tảng khác. Bản thân Python đi kèm với mô-đun

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72 trong thư viện chuẩn. Thông thường, chúng tôi sẽ trực tiếp sử dụng
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72 cho thời gian ở trên. Tuy nhiên,
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72 gặp khó khăn trong việc xác định thời gian nhập một cách đáng tin cậy vì Python rất thông minh khi chỉ nhập các mô-đun một lần. Xem xét ví dụ sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

9

Trong khi bạn nhận được kết quả, bạn nên nghi ngờ về kết quả. 0. 1 micro giây nhanh hơn 100000 lần so với những gì

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

67 đo được. Điều mà
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72 đã thực sự làm là chạy câu lệnh
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

78 30 triệu lần, trong khi Python thực sự chỉ nhập
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 một lần

Để có kết quả hợp lý, bạn có thể yêu cầu

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72 chỉ chạy một lần

String thing;
thing = "Hello";
0

Những kết quả này có cùng tỷ lệ với kết quả từ

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

67 ở trên. Tuy nhiên, vì chúng chỉ dựa trên một lần thực thi mã nên chúng không đáng tin cậy bằng những mã dựa trên nhiều lần chạy

Kết luận trong cả hai trường hợp này là việc nhập

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 mất vài mili giây. Đối với phần lớn các chương trình và tập lệnh bạn viết, điều này có thể không thành vấn đề

Tùy chọn

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

83 mới

Trong Trăn 3. 7 cũng có một tùy chọn dòng lệnh mới có thể được sử dụng để tính thời gian nhập. Sử dụng

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

84, bạn sẽ nhận được báo cáo về tất cả các lần nhập được thực hiện

String thing;
thing = "Hello";
1

Điều này cho thấy một kết quả tương tự. Nhập

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 mất khoảng 6 mili giây. Nếu bạn đọc kỹ báo cáo, bạn có thể nhận thấy rằng khoảng một nửa thời gian này được dành cho việc nhập các mô-đun
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

86 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

87 mà
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 phụ thuộc vào

Vì vậy, bạn có nên sử dụng kiểm tra kiểu tĩnh trong mã của riêng mình không? . May mắn thay, Python hỗ trợ khái niệm gõ dần dần. Điều này có nghĩa là bạn có thể dần dần đưa các loại vào mã của mình. Mã không có gợi ý loại sẽ bị trình kiểm tra loại tĩnh bỏ qua. Do đó, bạn có thể bắt đầu thêm các loại vào các thành phần quan trọng và tiếp tục miễn là nó tăng thêm giá trị cho bạn

Nhìn vào danh sách ưu và nhược điểm ở trên, bạn sẽ nhận thấy rằng việc thêm các loại sẽ không ảnh hưởng đến chương trình đang chạy của bạn hoặc người dùng chương trình của bạn. Kiểm tra loại nhằm mục đích làm cho cuộc sống của bạn với tư cách là một nhà phát triển tốt hơn và thuận tiện hơn

Một số quy tắc nhỏ về việc có nên thêm các loại vào dự án của bạn hay không là

  • Nếu bạn mới bắt đầu học Python, bạn có thể yên tâm chờ đợi với các gợi ý về loại cho đến khi bạn có nhiều kinh nghiệm hơn

  • Nhập gợi ý thêm ít giá trị trong các tập lệnh ngắn gọn

  • Trong các thư viện sẽ được người khác sử dụng, đặc biệt là những thư viện được xuất bản trên PyPI, các gợi ý nhập sẽ bổ sung rất nhiều giá trị. Mã khác sử dụng thư viện của bạn cần các gợi ý loại này để được kiểm tra đúng loại. Để biết ví dụ về các dự án sử dụng gợi ý loại, hãy xem

    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    89,
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    90, Trình đọc Python thực của riêng chúng tôi và chính Mypy

  • Trong các dự án lớn hơn, gợi ý nhập giúp bạn hiểu cách các loại chạy qua mã của bạn và rất được khuyến khích. Thậm chí nhiều hơn thế trong các dự án mà bạn hợp tác với những người khác

Trong bài báo xuất sắc của mình The State of Type Hints in Python Bernát Gábor khuyến nghị rằng “nên sử dụng các gợi ý về loại bất cứ khi nào các bài kiểm tra đơn vị đáng để viết. ” Thật vậy, gợi ý nhập đóng vai trò tương tự như các bài kiểm tra trong mã của bạn. họ giúp bạn với tư cách là nhà phát triển viết mã tốt hơn

Hy vọng rằng bây giờ bạn đã có ý tưởng về cách hoạt động của kiểm tra kiểu trong Python và liệu đó có phải là thứ bạn muốn sử dụng trong các dự án của riêng mình không

Trong phần còn lại của hướng dẫn này, chúng ta sẽ đi vào chi tiết hơn về hệ thống kiểu Python, bao gồm cách bạn chạy trình kiểm tra kiểu tĩnh [đặc biệt tập trung vào Mypy], cách bạn nhập mã kiểm tra sử dụng thư viện mà không cần gợi ý kiểu và cách bạn

Chú thích

Chú thích đã được giới thiệu trong Python 3. 0, ban đầu không có mục đích cụ thể. Chúng chỉ đơn giản là một cách để liên kết các biểu thức tùy ý với các đối số của hàm và trả về các giá trị

Nhiều năm sau, PEP 484 đã xác định cách thêm gợi ý kiểu vào mã Python của bạn, dựa trên công việc mà Jukka Lehtosalo đã thực hiện trên bằng tiến sĩ của mình. D. dự án—Mypy. Cách chính để thêm gợi ý loại là sử dụng chú thích. Vì việc kiểm tra kiểu ngày càng trở nên phổ biến, điều này cũng có nghĩa là các chú thích chủ yếu nên được dành riêng cho các gợi ý kiểu

Các phần tiếp theo giải thích cách chú thích hoạt động trong ngữ cảnh của gợi ý loại

Chú thích chức năng

Đối với các hàm, bạn có thể chú thích đối số và giá trị trả về. Điều này được thực hiện như sau

String thing;
thing = "Hello";
2

Đối với các đối số, cú pháp là

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

91, trong khi kiểu trả về được chú thích bằng cách sử dụng
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

92. Lưu ý rằng chú thích phải là biểu thức Python hợp lệ

Ví dụ đơn giản sau đây thêm chú thích cho hàm tính chu vi hình tròn

String thing;
thing = "Hello";
3

Khi chạy mã, bạn cũng có thể kiểm tra các chú thích. Chúng được lưu trữ trong một thuộc tính

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

93 đặc biệt trên hàm

>>>

String thing;
thing = "Hello";
4

Đôi khi bạn có thể bối rối về cách Mypy diễn giải các gợi ý loại của bạn. Đối với những trường hợp đó, có các biểu thức Mypy đặc biệt.

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

94 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

95. Bạn có thể thêm những mã này vào mã của mình trước khi chạy Mypy và Mypy sẽ báo cáo chính xác những loại mà nó đã suy luận. Ví dụ, lưu đoạn mã sau vào
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

96

String thing;
thing = "Hello";
5

Tiếp theo, chạy mã này thông qua Mypy

String thing;
thing = "Hello";
6

Ngay cả khi không có bất kỳ chú thích nào, Mypy đã suy ra chính xác các loại của

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

97 tích hợp, cũng như các biến cục bộ của chúng tôi là
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

98 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

99

Ghi chú. Các biểu thức tiết lộ chỉ có nghĩa là một công cụ giúp bạn thêm các loại và gỡ lỗi các gợi ý về loại của bạn. Nếu bạn cố chạy tệp

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

96 dưới dạng tập lệnh Python, nó sẽ gặp sự cố với
String thing;
thing = "Hello";
01 vì
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

94 không phải là hàm được trình thông dịch Python biết đến

Nếu Mypy nói rằng "Tên '

String thing;
thing = "Hello";
03' không được xác định", bạn có thể cần cập nhật cài đặt Mypy của mình. Biểu thức
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

95 có sẵn trong Mypy phiên bản 0. 610 trở lên

Loại bỏ các quảng cáo

Chú thích biến

Trong định nghĩa của

String thing;
thing = "Hello";
05 ở phần trước, bạn chỉ chú thích đối số và giá trị trả về. Bạn đã không thêm bất kỳ chú thích nào bên trong thân hàm. Thường xuyên hơn không, điều này là đủ

Tuy nhiên, đôi khi trình kiểm tra loại cũng cần trợ giúp trong việc tìm ra các loại biến. Các chú thích biến được định nghĩa trong PEP 526 và được giới thiệu trong Python 3. 6. Cú pháp giống như đối với chú thích đối số hàm

String thing;
thing = "Hello";
7

Biến

String thing;
thing = "Hello";
06 đã được chú thích với gợi ý kiểu
String thing;
thing = "Hello";
07

Ghi chú. Trình kiểm tra loại tĩnh có nhiều khả năng phát hiện ra rằng

String thing;
thing = "Hello";
08 là số float, vì vậy trong ví dụ này, chú thích của
String thing;
thing = "Hello";
06 là không cần thiết. Khi tìm hiểu thêm về hệ thống kiểu Python, bạn sẽ thấy nhiều ví dụ liên quan hơn về chú thích biến

Chú thích của các biến được lưu trữ trong từ điển

String thing;
thing = "Hello";
10 cấp mô-đun

>>>

String thing;
thing = "Hello";
8

Bạn được phép chú thích một biến mà không cần đặt giá trị cho nó. Điều này thêm chú thích vào từ điển

String thing;
thing = "Hello";
10, trong khi biến vẫn chưa được xác định

>>>

String thing;
thing = "Hello";
9

Vì không có giá trị nào được gán cho

String thing;
thing = "Hello";
12 nên tên
String thing;
thing = "Hello";
12 vẫn chưa được xác định

Loại Nhận xét

Như đã đề cập, các chú thích đã được giới thiệu trong Python 3 và chúng chưa được nhập vào Python 2. Điều này có nghĩa là nếu bạn đang viết mã cần hỗ trợ Python cũ, thì bạn không thể sử dụng chú thích

Thay vào đó, bạn có thể sử dụng loại bình luận. Đây là những nhận xét được định dạng đặc biệt có thể được sử dụng để thêm gợi ý loại tương thích với mã cũ hơn. Để thêm nhận xét loại vào một chức năng, bạn làm như thế này

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

70

Các nhận xét loại chỉ là nhận xét, vì vậy chúng có thể được sử dụng trong bất kỳ phiên bản Python nào

Nhận xét loại được xử lý trực tiếp bởi trình kiểm tra loại, vì vậy những loại này không có trong từ điển

String thing;
thing = "Hello";
10

>>>

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

71

Một nhận xét loại phải bắt đầu bằng chữ

String thing;
thing = "Hello";
15 và nằm trên cùng một dòng hoặc dòng sau với định nghĩa hàm. Nếu bạn muốn chú thích một hàm có nhiều đối số, bạn viết từng loại cách nhau bằng dấu phẩy

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

72

Bạn cũng được phép viết mỗi đối số trên một dòng riêng biệt với chú thích riêng của nó

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

73

Chạy ví dụ thông qua Python và Mypy

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

74

Nếu bạn gặp lỗi, chẳng hạn nếu bạn tình cờ gọi cho

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

42 với
String thing;
thing = "Hello";
17 trên dòng 10, Mypy sẽ cho bạn biết

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

75

Bạn cũng có thể thêm nhận xét kiểu vào biến. Điều này được thực hiện tương tự như cách bạn thêm nhận xét loại vào đối số

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

76

Trong ví dụ này,

String thing;
thing = "Hello";
06 sẽ được kiểm tra kiểu dưới dạng biến float

Loại bỏ các quảng cáo

Vì vậy, Nhập Chú thích hoặc Nhập Nhận xét?

Bạn có nên sử dụng chú thích hoặc nhập nhận xét khi thêm gợi ý loại vào mã của riêng mình không? . Sử dụng chú thích nếu bạn có thể, sử dụng nhận xét loại nếu bạn phải

Chú thích cung cấp cú pháp rõ ràng hơn để giữ thông tin loại gần với mã của bạn hơn. Chúng cũng là cách viết gợi ý loại chính thức được đề xuất và sẽ được phát triển thêm cũng như duy trì đúng cách trong tương lai

Loại nhận xét dài dòng hơn và có thể xung đột với các loại nhận xét khác trong mã của bạn như chỉ thị kẻ nói dối. Tuy nhiên, chúng có thể được sử dụng trong các cơ sở mã không hỗ trợ chú thích

Ngoài ra còn có tùy chọn ẩn số ba. tập tin sơ khai. Bạn sẽ tìm hiểu về những điều này sau, khi chúng ta thảo luận về việc thêm các loại vào thư viện của bên thứ ba

Các tệp sơ khai sẽ hoạt động trong mọi phiên bản Python, với chi phí phải duy trì một bộ tệp thứ hai. Nói chung, bạn chỉ muốn sử dụng các tệp sơ khai nếu bạn không thể thay đổi mã nguồn ban đầu

Chơi với các loại Python, Phần 1

Cho đến bây giờ, bạn chỉ sử dụng các loại cơ bản như

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28,
String thing;
thing = "Hello";
07 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 trong gợi ý loại của mình. Hệ thống loại Python khá mạnh và hỗ trợ nhiều loại phức tạp hơn. Điều này là cần thiết vì nó cần có khả năng mô hình hóa hợp lý bản chất gõ vịt năng động của Python

Trong phần này, bạn sẽ tìm hiểu thêm về hệ thống loại này, trong khi thực hiện một trò chơi bài đơn giản. Bạn sẽ thấy cách chỉ định

  • Loại trình tự và ánh xạ như bộ dữ liệu, danh sách và từ điển
  • Nhập bí danh giúp mã dễ đọc hơn
  • Các hàm và phương thức đó không trả về bất cứ thứ gì
  • Các đối tượng có thể thuộc bất kỳ loại nào

Sau một thời gian ngắn đi vào một số lý thuyết về loại, bạn sẽ thấy nhiều cách hơn nữa để chỉ định các loại trong Python. Bạn có thể tìm thấy các ví dụ về mã từ phần này tại đây

Ví dụ. Một cỗ bài

Ví dụ sau đây cho thấy việc triển khai một bộ bài thông thường [tiếng Pháp]

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

77

Mỗi thẻ được biểu diễn dưới dạng một bộ chuỗi biểu thị chất và thứ hạng. Bộ bài được thể hiện dưới dạng một danh sách các quân bài.

String thing;
thing = "Hello";
22 tạo một cỗ bài thông thường gồm 52 quân bài và tùy chọn xáo trộn các quân bài.
String thing;
thing = "Hello";
23 chia bộ bài cho bốn người chơi

Cuối cùng,

String thing;
thing = "Hello";
24 chơi trò chơi. Hiện tại, nó chỉ chuẩn bị cho một trò chơi bài bằng cách xây dựng một cỗ bài xáo trộn và chia bài cho từng người chơi. Sau đây là một đầu ra điển hình

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

78

Bạn sẽ thấy cách mở rộng ví dụ này thành một trò chơi thú vị hơn khi chúng ta tiếp tục

Trình tự và ánh xạ

Hãy thêm gợi ý loại vào trò chơi bài của chúng tôi. Nói cách khác, hãy chú thích các hàm

String thing;
thing = "Hello";
22,
String thing;
thing = "Hello";
23 và
String thing;
thing = "Hello";
24. Thách thức đầu tiên là bạn cần chú thích các loại tổng hợp như danh sách được sử dụng để đại diện cho cỗ bài và bộ dữ liệu được sử dụng để đại diện cho chính các quân bài

Với các loại đơn giản như

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28,
String thing;
thing = "Hello";
07 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39, việc thêm gợi ý loại dễ dàng như sử dụng chính loại đó

>>>

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

79

Với các loại hỗn hợp, bạn được phép làm tương tự

>>>

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
10

Tuy nhiên, điều này không thực sự nói lên toàn bộ câu chuyện. Các loại

String thing;
thing = "Hello";
31,
String thing;
thing = "Hello";
32 và
String thing;
thing = "Hello";
33 sẽ là gì? . Tuy nhiên, bản thân các gợi ý loại không cung cấp thông tin về điều này

Thay vào đó, bạn nên sử dụng các loại đặc biệt được xác định trong mô-đun

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62. Các loại này thêm cú pháp để chỉ định các loại phần tử của các loại tổng hợp. Bạn có thể viết như sau

>>>

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
11

Lưu ý rằng mỗi loại trong số này bắt đầu bằng chữ in hoa và tất cả chúng đều sử dụng dấu ngoặc vuông để xác định loại mục

  • String thing;
    thing = "Hello";
    
    38 là một danh sách các chuỗi
  • String thing;
    thing = "Hello";
    
    39 là một bộ 3 bao gồm ba số nguyên
  • String thing;
    thing = "Hello";
    
    40 là một chuỗi từ điển ánh xạ tới các giá trị Boolean

Mô-đun

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 chứa nhiều loại hỗn hợp hơn, bao gồm
String thing;
thing = "Hello";
42,
String thing;
thing = "Hello";
43,
String thing;
thing = "Hello";
44,
String thing;
thing = "Hello";
45 và
String thing;
thing = "Hello";
46. Ngoài ra, mô-đun bao gồm các loại khác mà bạn sẽ thấy trong các phần sau

Hãy trở lại với trò chơi bài. Một thẻ được đại diện bởi một bộ gồm hai chuỗi. Bạn có thể viết cái này là

String thing;
thing = "Hello";
47, vì vậy loại bộ bài sẽ trở thành
String thing;
thing = "Hello";
48. Do đó, bạn có thể chú thích
String thing;
thing = "Hello";
22 như sau

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
12

Ngoài giá trị trả về, bạn cũng đã thêm loại

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 vào đối số tùy chọn
String thing;
thing = "Hello";
51

Ghi chú. Tuples và danh sách được chú thích khác nhau

Bộ dữ liệu là một chuỗi bất biến và thường bao gồm một số lượng cố định các phần tử có thể được nhập khác nhau. Ví dụ: chúng tôi đại diện cho một thẻ dưới dạng một bộ phù hợp và xếp hạng. Nói chung, bạn viết

String thing;
thing = "Hello";
52 cho một n-tuple

Danh sách là một dãy có thể thay đổi và thường bao gồm một số phần tử cùng loại không xác định, ví dụ: danh sách các thẻ. Cho dù có bao nhiêu phần tử trong danh sách thì chỉ có một loại trong chú thích.

String thing;
thing = "Hello";
53

Trong nhiều trường hợp, các chức năng của bạn sẽ mong đợi một số loại trình tự và không thực sự quan tâm đó là danh sách hay bộ dữ liệu. In these cases you should use

String thing;
thing = "Hello";
54 when annotating the function argument

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
13

Sử dụng

String thing;
thing = "Hello";
55 là một ví dụ về cách sử dụng kiểu gõ vịt.
String thing;
thing = "Hello";
55 là bất kỳ thứ gì hỗ trợ
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20 và
String thing;
thing = "Hello";
58, độc lập với loại thực tế của nó

Loại bỏ các quảng cáo

Nhập bí danh

The type hints might become quite oblique when working with nested types like the deck of cards. Bạn có thể cần phải nhìn chằm chằm vào

String thing;
thing = "Hello";
48 một chút trước khi nhận ra rằng nó khớp với biểu tượng của chúng ta về một cỗ bài

Now consider how you would annotate

String thing;
thing = "Hello";
23

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
14

That’s just terrible

Recall that type annotations are regular Python expressions. That means that you can define your own type aliases by assigning them to new variables. Ví dụ, bạn có thể tạo bí danh loại

String thing;
thing = "Hello";
61 và
String thing;
thing = "Hello";
62

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
15

String thing;
thing = "Hello";
61 hiện có thể được sử dụng trong gợi ý loại hoặc trong định nghĩa bí danh loại mới, như
String thing;
thing = "Hello";
62 trong ví dụ trên

Sử dụng các bí danh này, các chú thích của

String thing;
thing = "Hello";
23 trở nên dễ đọc hơn nhiều

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
16

Bí danh loại rất tốt để làm cho mã của bạn và ý định của nó rõ ràng hơn. Đồng thời, những bí danh này có thể được kiểm tra để xem những gì chúng đại diện

>>>

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
17

Lưu ý rằng khi in

String thing;
thing = "Hello";
62, nó hiển thị rằng đó là bí danh cho danh sách 2 bộ chuỗi

Các hàm không có giá trị trả về

Bạn có thể biết rằng các hàm không có trả về rõ ràng vẫn trả về

String thing;
thing = "Hello";
67

>>>

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
18

Mặc dù các chức năng như vậy về mặt kỹ thuật trả về một cái gì đó, nhưng giá trị trả về đó không hữu ích. Bạn nên thêm gợi ý loại bằng cách sử dụng

String thing;
thing = "Hello";
67 cũng như loại trả về

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
19

Các chú thích giúp phát hiện các loại lỗi tinh vi mà bạn đang cố gắng sử dụng một giá trị trả về vô nghĩa. Mypy sẽ cung cấp cho bạn một cảnh báo hữu ích

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
90

Lưu ý rằng rõ ràng về một hàm không trả về bất cứ thứ gì khác với việc không thêm gợi ý kiểu về giá trị trả về

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
91

Trong trường hợp sau này, Mypy không có thông tin về giá trị trả về nên nó sẽ không tạo ra bất kỳ cảnh báo nào

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
92

Trong một trường hợp kỳ lạ hơn, lưu ý rằng bạn cũng có thể chú thích các chức năng không bao giờ được mong đợi sẽ trở lại bình thường. Điều này được thực hiện bằng cách sử dụng

String thing;
thing = "Hello";
69

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
93

String thing;
thing = "Hello";
70 luôn đưa ra một ngoại lệ, nên nó sẽ không bao giờ trả về đúng cách

Loại bỏ các quảng cáo

Ví dụ. Chơi một số thẻ

Hãy quay lại ví dụ về trò chơi bài của chúng tôi. Trong phiên bản thứ hai này của trò chơi, chúng tôi chia bài cho mỗi người chơi như trước đây. Sau đó, một người chơi bắt đầu được chọn và những người chơi lần lượt chơi bài của họ. Tuy nhiên, thực sự không có bất kỳ quy tắc nào trong trò chơi, vì vậy người chơi sẽ chỉ chơi các quân bài ngẫu nhiên.

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
94

Lưu ý rằng ngoài việc thay đổi

String thing;
thing = "Hello";
24, chúng tôi đã thêm hai chức năng mới cần gợi ý loại.
String thing;
thing = "Hello";
72 và
String thing;
thing = "Hello";
73. Trước khi thảo luận về cách chúng tôi sẽ thêm gợi ý loại cho chúng, đây là một kết quả ví dụ khi chạy trò chơi

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
95

Trong ví dụ này, người chơi

String thing;
thing = "Hello";
74 được chọn ngẫu nhiên làm người chơi bắt đầu. Đổi lại, mỗi người chơi đánh một quân bài. đầu tiên là
String thing;
thing = "Hello";
74, sau đó là
String thing;
thing = "Hello";
76, sau đó là
String thing;
thing = "Hello";
77 và cuối cùng là
String thing;
thing = "Hello";
78. Người chơi tiếp tục chơi bài miễn là họ còn bài trong tay

Loại
String thing;
thing = "Hello";
79

String thing;
thing = "Hello";
72 hoạt động cho cả danh sách tên và danh sách thẻ [và bất kỳ trình tự nào khác cho vấn đề đó]. Một cách để thêm gợi ý loại cho điều này sẽ như sau

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
96

Điều này ít nhiều có nghĩa là những gì nó nói.

String thing;
thing = "Hello";
81 là một chuỗi có thể chứa các mục thuộc bất kỳ loại nào và
String thing;
thing = "Hello";
72 sẽ trả về một mục như vậy thuộc bất kỳ loại nào. Thật không may, điều này không hữu ích. Xem xét ví dụ sau

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
97

Mặc dù Mypy sẽ suy luận chính xác rằng

String thing;
thing = "Hello";
38 là một danh sách các chuỗi, nhưng thông tin đó sẽ bị mất sau khi gọi tới
String thing;
thing = "Hello";
72 do sử dụng loại
String thing;
thing = "Hello";
79

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
98

Bạn sẽ sớm thấy một cách tốt hơn. Tuy nhiên, trước tiên, chúng ta hãy có một cái nhìn lý thuyết hơn về hệ thống kiểu Python và vai trò đặc biệt của

String thing;
thing = "Hello";
79

Loại lý thuyết

Hướng dẫn này chủ yếu là một hướng dẫn thực tế và chúng tôi sẽ chỉ vạch ra bề nổi của lý thuyết làm cơ sở cho các gợi ý về loại Python. Để biết thêm chi tiết PEP 483 là một điểm khởi đầu tốt. Nếu bạn muốn quay lại các ví dụ thực tế, vui lòng chuyển sang phần tiếp theo

tiểu loại

Một khái niệm quan trọng là các kiểu con. Chính thức, chúng tôi nói rằng một loại

String thing;
thing = "Hello";
87 là một loại con của
String thing;
thing = "Hello";
88 nếu hai điều kiện sau thỏa mãn

  • Mọi giá trị từ
    String thing;
    thing = "Hello";
    
    87 cũng nằm trong tập hợp các giá trị của loại
    String thing;
    thing = "Hello";
    
    88
  • Mọi chức năng từ loại
    String thing;
    thing = "Hello";
    
    88 cũng nằm trong tập hợp các chức năng của loại
    String thing;
    thing = "Hello";
    
    87

Hai điều kiện này đảm bảo rằng ngay cả khi loại

String thing;
thing = "Hello";
87 khác với
String thing;
thing = "Hello";
88, các biến loại
String thing;
thing = "Hello";
87 luôn có thể giả vờ là
String thing;
thing = "Hello";
88

Để có một ví dụ cụ thể, hãy xem xét

String thing;
thing = "Hello";
97 và
String thing;
thing = "Hello";
98. Loại
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 chỉ nhận hai giá trị. Thông thường, chúng được ký hiệu là
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

40 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

33, nhưng những tên này chỉ là bí danh cho các giá trị số nguyên lần lượt là
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

702 và
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

703

>>>

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
99

Vì 0 và 1 đều là số nguyên nên điều kiện đầu tiên thỏa mãn. Ở trên, bạn có thể thấy rằng Booleans có thể được cộng lại với nhau, nhưng chúng cũng có thể làm bất cứ điều gì khác mà số nguyên có thể. Đây là điều kiện thứ hai ở trên. Nói cách khác,

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 là một kiểu con của
String thing;
thing = "Hello";
35

Tầm quan trọng của các kiểu con là một kiểu con luôn có thể giả vờ là siêu kiểu của nó. Chẳng hạn, loại mã sau đây kiểm tra là chính xác

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

30

Các kiểu con có phần nào liên quan đến các lớp con. Trên thực tế, tất cả các lớp con tương ứng với các kiểu con và

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 là một kiểu con của
String thing;
thing = "Hello";
35 vì
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 là một lớp con của
String thing;
thing = "Hello";
35. Tuy nhiên, cũng có những kiểu con không tương ứng với lớp con. Chẳng hạn,
String thing;
thing = "Hello";
35 là một kiểu con của
String thing;
thing = "Hello";
07, nhưng
String thing;
thing = "Hello";
35 không phải là một lớp con của
String thing;
thing = "Hello";
07

Loại bỏ các quảng cáo

Covariant, Contravariant, và Invariant

What happens when you use subtypes inside composite types? For instance, is

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

714 a subtype of
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

715? The answer depends on the composite type, and whether that type is covariant, contravariant, or invariant. Điều này trở nên nhanh chóng về mặt kỹ thuật, vì vậy hãy chỉ đưa ra một vài ví dụ

  • >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    716 là hiệp phương sai. Điều này có nghĩa là nó duy trì phân cấp loại của các loại mục của nó.
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    714 is a subtype of
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    715 because
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    39 is a subtype of
    String thing;
    thing = "Hello";
    
    35

  • >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    721 là bất biến. Các kiểu bất biến không đảm bảo về các kiểu con. Mặc dù tất cả các giá trị của
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    722 đều là giá trị của
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    723, nhưng bạn có thể nối thêm
    String thing;
    thing = "Hello";
    
    35 vào
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    723 chứ không phải vào
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    722. Nói cách khác, điều kiện thứ hai cho các kiểu con không thỏa mãn và
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    722 không phải là kiểu con của
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    723

  • >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    729 is contravariant in its arguments. Điều này có nghĩa là nó đảo ngược hệ thống phân cấp loại. You will see how
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    729 works later, but for now think of
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    731 as a function with its only argument being of type
    String thing;
    thing = "Hello";
    
    87. Một ví dụ về
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    733 là hàm
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    734 được xác định ở trên. Ngược lại có nghĩa là nếu một chức năng hoạt động trên
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    39 được mong đợi, thì một chức năng hoạt động trên
    String thing;
    thing = "Hello";
    
    35 sẽ được chấp nhận

Nói chung, bạn không cần phải giữ những biểu thức này thẳng. Tuy nhiên, bạn nên lưu ý rằng các kiểu con và kiểu tổng hợp có thể không đơn giản và trực quan

Nhập dần dần và các loại nhất quán

Earlier we mentioned that Python supports gradual typing, where you can gradually add type hints to your Python code. Gradual typing is essentially made possible by the

String thing;
thing = "Hello";
79 type

Somehow

String thing;
thing = "Hello";
79 sits both at the top and at the bottom of the type hierarchy of subtypes. Any type behaves as if it is a subtype of
String thing;
thing = "Hello";
79, and
String thing;
thing = "Hello";
79 behaves as if it is a subtype of any other type. Looking at the definition of subtypes above this is not really possible. Instead we talk about consistent types

Loại

String thing;
thing = "Hello";
87 phù hợp với loại
String thing;
thing = "Hello";
88 nếu
String thing;
thing = "Hello";
87 là một loại con của
String thing;
thing = "Hello";
88 hoặc một trong hai
String thing;
thing = "Hello";
87 hoặc
String thing;
thing = "Hello";
88 là
String thing;
thing = "Hello";
79

The type checker only complains about inconsistent types. The takeaway is therefore that you will never see type errors arising from the

String thing;
thing = "Hello";
79 type

This means that you can use

String thing;
thing = "Hello";
79 to explicitly fall back to dynamic typing, describe types that are too complex to describe in the Python type system, or describe items in composite types. For instance, a dictionary with string keys that can take any type as its values can be annotated
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

750

Do remember, though, if you use

String thing;
thing = "Hello";
79 the static type checker will effectively not do any type any checking

Playing With Python Types, Part 2

Let’s return to our practical examples. Recall that you were trying to annotate the general

String thing;
thing = "Hello";
72 function

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
96

The problem with using

String thing;
thing = "Hello";
79 is that you are needlessly losing type information. You know that if you pass a list of strings to
String thing;
thing = "Hello";
72, it will return a string. Below you’ll see how to express this using type variables, as well as how to work with

  • Duck types and protocols
  • Arguments with
    String thing;
    thing = "Hello";
    
    67 as default value
  • Class methods
  • The type of your own classes
  • Variable number of arguments

Type Variables

A type variable is a special variable that can take on any type, depending on the situation

Let’s create a type variable that will effectively encapsulate the behavior of

String thing;
thing = "Hello";
72

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

32

A type variable must be defined using

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

757 from the
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 module. When used, a type variable ranges over all possible types and takes the most specific type possible. In the example,
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

759 is now a
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

33

Consider a few other examples

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

34

The first two examples should have type

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28 and
String thing;
thing = "Hello";
35, but what about the last two? The individual list items have different types, and in that case the
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

763 type variable does its best to accommodate

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

35

As you’ve already seen

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

39 is a subtype of
String thing;
thing = "Hello";
35, which again is a subtype of
String thing;
thing = "Hello";
07. So in the third example the return value of
String thing;
thing = "Hello";
72 is guaranteed to be something that can be thought of as a
String thing;
thing = "Hello";
07. In the last example, there is no subtype relationship between
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28 and
String thing;
thing = "Hello";
35, so the best that can be said about the return value is that it is an object

Note that none of these examples raised a type error. Is there a way to tell the type checker that

String thing;
thing = "Hello";
72 should accept both strings and numbers, but not both at the same time?

You can constrain type variables by listing the acceptable types

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

36

Now

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

763 can only be either
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28 or
String thing;
thing = "Hello";
07, and Mypy will note that the last example is an error

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

37

Also note that in the second example the type is considered

String thing;
thing = "Hello";
07 even though the input list only contains
String thing;
thing = "Hello";
35 objects. This is because
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

763 was restricted to strings and floats and
String thing;
thing = "Hello";
35 is a subtype of
String thing;
thing = "Hello";
07

In our card game we want to restrict

String thing;
thing = "Hello";
72 to be used for
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28 and
String thing;
thing = "Hello";
61

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

38

We briefly mentioned that

String thing;
thing = "Hello";
55 represents both lists and tuples. Như chúng tôi đã lưu ý, một
String thing;
thing = "Hello";
55 có thể được coi là một loại vịt, vì nó có thể là bất kỳ đối tượng nào có triển khai
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

21 và
String thing;
thing = "Hello";
58

Loại bỏ các quảng cáo

Duck Types and Protocols

Recall the following example from the introduction

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
1

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20 can return the length of any object that has implemented the
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

21 method. How can we add type hints to
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20, and in particular the
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

26 argument?

The answer hides behind the academic sounding term structural subtyping. One way to categorize type systems is by whether they are nominal or structural

  • In a nominal system, comparisons between types are based on names and declarations. The Python type system is mostly nominal, where an

    String thing;
    thing = "Hello";
    
    35 can be used in place of a
    String thing;
    thing = "Hello";
    
    07 because of their subtype relationship

  • In a structural system, comparisons between types are based on structure. You could define a structural type

    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    793 that includes all instances that define
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    21, irrespective of their nominal type

There is ongoing work to bring a full-fledged structural type system to Python through PEP 544 which aims at adding a concept called protocols. Most of PEP 544 is already implemented in Mypy though

A protocol specifies one or more methods that must be implemented. For example, all classes defining

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

21 fulfill the
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

796 protocol. We can therefore annotate
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20 as follows

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

40

Other examples of protocols defined in the

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

62 module include
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

799,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
100,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
101, and
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
102

You can also define your own protocols. This is done by inheriting from

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
103 and defining the function signatures [with empty function bodies] that the protocol expects. The following example shows how
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

20 and
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

793 could have been implemented

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

41

At the time of writing the support for self-defined protocols is still experimental and only available through the

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
106 module. This module must be explicitly installed from PyPI by doing
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
107

The
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
108 Type

A common pattern in Python is to use

String thing;
thing = "Hello";
67 as a default value for an argument. This is usually done either to avoid problems with mutable default values or to have a sentinel value flagging special behavior

In the card example, the

String thing;
thing = "Hello";
73 function uses
String thing;
thing = "Hello";
67 as a sentinel value for
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
112 saying that if no start player is given it should be chosen randomly

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

42

The challenge this creates for type hinting is that in general

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
112 should be a string. However, it may also take the special non-string value
String thing;
thing = "Hello";
67

In order to annotate such arguments you can use the

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
108 type

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

43

The

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
108 type simply says that a variable either has the type specified or is
String thing;
thing = "Hello";
67. An equivalent way of specifying the same would be using the
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
118 type.
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
119

Lưu ý rằng khi sử dụng

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
108 hoặc
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
118, bạn phải lưu ý rằng biến có đúng loại khi bạn thao tác trên biến đó. This is done in the example by testing whether
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
122. Not doing so would cause both static type errors as well as possible runtime errors

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

44

Mypy tells you that you have not taken care of the case where

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
112 is
String thing;
thing = "Hello";
67

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

45

Note. Việc sử dụng

String thing;
thing = "Hello";
67 cho các đối số tùy chọn phổ biến đến mức Mypy tự động xử lý nó. Mypy giả định rằng một đối số mặc định của
String thing;
thing = "Hello";
67 biểu thị một đối số tùy chọn ngay cả khi gợi ý loại không nói rõ ràng như vậy. You could have used the following

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

46

Nếu bạn không muốn Mypy đưa ra giả định này, bạn có thể tắt nó bằng tùy chọn dòng lệnh

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
127

Loại bỏ các quảng cáo

Ví dụ. Mục tiêu] của trò chơi

Hãy viết lại trò chơi bài để hướng đối tượng hơn. Điều này sẽ cho phép chúng ta thảo luận về cách chú thích đúng các lớp và phương thức

Một bản dịch ít nhiều trực tiếp trò chơi bài của chúng tôi thành mã sử dụng các lớp cho

String thing;
thing = "Hello";
61,
String thing;
thing = "Hello";
62,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
130 và
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
131 trông giống như sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

47

Bây giờ hãy thêm các loại vào mã này

Nhập gợi ý cho phương pháp

Trước hết, các gợi ý kiểu cho các phương thức hoạt động giống như các gợi ý kiểu cho các hàm. Sự khác biệt duy nhất là đối số

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 không cần chú thích, vì nó sẽ luôn là một thể hiện của lớp. Các loại của lớp
String thing;
thing = "Hello";
61 rất dễ thêm

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

48

Lưu ý rằng phương thức

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
134 luôn phải có
String thing;
thing = "Hello";
67 làm kiểu trả về của nó

Các lớp dưới dạng các loại

Có sự tương ứng giữa các lớp và các loại. Ví dụ: tất cả các thể hiện của lớp

String thing;
thing = "Hello";
61 cùng nhau tạo thành loại
String thing;
thing = "Hello";
61. Để sử dụng các lớp làm kiểu, bạn chỉ cần sử dụng tên của lớp

Ví dụ: một

String thing;
thing = "Hello";
62 về cơ bản bao gồm một danh sách các đối tượng
String thing;
thing = "Hello";
61. Bạn có thể chú thích điều này như sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

49

Mypy có thể kết nối việc bạn sử dụng

String thing;
thing = "Hello";
61 trong chú thích với định nghĩa của lớp
String thing;
thing = "Hello";
61

Điều này không hoạt động rõ ràng mặc dù khi bạn cần tham khảo lớp hiện đang được xác định. Ví dụ, phương thức của lớp

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
142 trả về một đối tượng có kiểu
String thing;
thing = "Hello";
62. Tuy nhiên, bạn không thể chỉ cần thêm
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
144 vì lớp
String thing;
thing = "Hello";
62 chưa được xác định đầy đủ

Thay vào đó, bạn được phép sử dụng chuỗi ký tự trong chú thích. Các chuỗi này sẽ chỉ được đánh giá bởi trình kiểm tra loại sau này và do đó có thể chứa các tham chiếu tự và chuyển tiếp. Phương thức

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
146 nên sử dụng các chuỗi ký tự như vậy cho các loại của nó

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

90

Lưu ý rằng lớp

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
130 cũng sẽ tham chiếu đến lớp
String thing;
thing = "Hello";
62. Tuy nhiên, điều này không có vấn đề gì, vì
String thing;
thing = "Hello";
62 được xác định trước
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
130

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

91

Thông thường chú thích không được sử dụng trong thời gian chạy. Điều này đã chắp cánh cho ý tưởng trì hoãn việc đánh giá các chú thích. Thay vì đánh giá các chú thích dưới dạng biểu thức Python và lưu trữ giá trị của chúng, đề xuất là lưu trữ biểu diễn chuỗi của chú thích và chỉ đánh giá nó khi cần

Chức năng như vậy được lên kế hoạch để trở thành tiêu chuẩn trong Python 4 vẫn còn là thần thoại. 0. Tuy nhiên, trong Python 3. 7 trở lên, các tham chiếu chuyển tiếp có sẵn thông qua quá trình nhập

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
151

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

92

Với việc nhập

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
151, bạn có thể sử dụng
String thing;
thing = "Hello";
62 thay vì
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
154 ngay cả trước khi
String thing;
thing = "Hello";
62 được xác định

Trả lại
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 hoặc
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
157

Như đã lưu ý, thông thường bạn không nên chú thích các đối số

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 hoặc
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
157. Một phần, điều này là không cần thiết vì
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 trỏ đến một thể hiện của lớp, vì vậy nó sẽ có kiểu của lớp. Trong ví dụ về
String thing;
thing = "Hello";
61,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 có kiểu ngầm định là
String thing;
thing = "Hello";
61. Ngoài ra, việc thêm loại này một cách rõ ràng sẽ rất cồng kềnh vì lớp chưa được xác định. Bạn sẽ phải sử dụng cú pháp chuỗi ký tự,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
164

Tuy nhiên, có một trường hợp bạn có thể muốn chú thích

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 hoặc
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
157. Xem xét điều gì sẽ xảy ra nếu bạn có một siêu lớp mà các lớp khác kế thừa từ đó và có các phương thức trả về
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 hoặc
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
157

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

93

Trong khi mã chạy không có vấn đề, Mypy sẽ đánh dấu sự cố

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

94

Vấn đề là mặc dù các phương thức kế thừa

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
169 và
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
170 sẽ trả về một
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
171 nhưng chú thích nói rằng chúng trả về một
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
172

In cases like this you want to be more careful to make sure the annotation is correct. The return type should match the type of

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 or the instance type of
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
157. This can be done using type variables that keep track of what is actually passed to
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
132 and
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
157

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

95

There are a few things to note in this example

  • The type variable

    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    177 is used to denote that return values might be instances of subclasses of
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    172

  • Chúng tôi xác định rằng

    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    172 là giới hạn trên của
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    177. Specifying
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    181 means that
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    177 will only be
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    172 or one of its subclasses. This is needed to properly restrict the types that are allowed

  • The

    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    184 construct is the typing equivalent of
    >>> thing = "Hello"
    >>> type[thing]
    
    
    >>> thing = 28.1
    >>> type[thing]
    
    
    13. You need it to note that the class method expects a class and returns an instance of that class

Annotating
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
186 and
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
187

In the object oriented version of the game, we added the option to name the players on the command line. This is done by listing player names after the name of the program

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

96

This is implemented by unpacking and passing in

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
188 to
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
189 when it’s instantiated. The
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
134 method uses
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
191 to pack the given names into a tuple

Regarding type annotations. even though

String thing;
thing = "Hello";
38 will be a tuple of strings, you should only annotate the type of each name. In other words, you should use
>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

28 and not
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
194

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

97

Similarly, if you have a function or method accepting

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
187, then you should only annotate the type of each possible keyword argument

Callables

Functions are first-class objects in Python. This means that you can use functions as arguments to other functions. That also means that you need to be able to add type hints representing functions

Functions, as well as lambdas, methods and classes, are represented by

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
196. The types of the arguments and the return value are usually also represented. For instance,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
197 represents a function with three arguments with types
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
198,
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
199, and
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
900, respectively. The return type of the function is
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
901

In the following example, the function

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
902 calls a given function twice and prints the return values

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

98

Note the annotation of the

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
903 argument to
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
902 on line 5. It says that
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
903 should be a callable with one string argument, that also returns a string. One example of such a callable is
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
906 defined on line 9

Most callable types can be annotated in a similar manner. However, if you need more flexibility, check out callback protocols and extended callable types

Example. Hearts

Let’s end with a full example of the game of Hearts. You might already know this game from other computer simulations. Here is a quick recap of the rules

  • Four players play with a hand of 13 cards each

  • The player holding the ♣2 starts the first round, and must play ♣2

  • Players take turns playing cards, following the leading suit if possible

  • The player playing the highest card in the leading suit wins the trick, and becomes start player in the next turn

  • A player can not lead with a ♡ until a ♡ has already been played in an earlier trick

  • Sau khi tất cả các thẻ được chơi, người chơi sẽ nhận được điểm nếu họ lấy một số thẻ nhất định

    • 13 points for the ♠Q
    • 1 điểm cho mỗi ♡
  • A game lasts several rounds, until one player has 100 points or more. The player with the least points wins

More details can be found found online

There are not many new typing concepts in this example that you have not already seen. We’ll therefore not go through this code in detail, but leave it as an example of annotated code

Source Code for the Hearts Card GameShow/Hide

You can download this code and other examples from GitHub

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

99

Dưới đây là một vài điểm cần lưu ý trong mã

  • Đối với các mối quan hệ loại khó thể hiện bằng cách sử dụng biến

    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    118 hoặc loại, bạn có thể sử dụng trình trang trí
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    908. Xem
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    909 để biết ví dụ và tài liệu để biết thêm thông tin

  • Các lớp con tương ứng với các kiểu con, do đó có thể sử dụng

    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    910 ở bất cứ đâu mong đợi một
    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    130

  • Khi một lớp con hiện thực lại một phương thức từ một lớp cha, các chú thích kiểu phải khớp với. Xem

    >>> if False:
    ..     1 + "two"  # This line never runs, so no TypeError is raised
    .. else:
    ..     1 + 2
    ...
    3
    
    >>> 1 + "two"  # Now this is type checked, and a TypeError is raised
    TypeError: unsupported operand type[s] for +: 'int' and 'str'
    
    912 để biết ví dụ

Khi bắt đầu trò chơi, bạn điều khiển người chơi đầu tiên. Nhập số để chọn thẻ để chơi. Sau đây là một ví dụ về cách chơi trò chơi, với các dòng được đánh dấu cho biết nơi người chơi đưa ra lựa chọn

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

40

Kiểm tra loại tĩnh

Cho đến giờ, bạn đã biết cách thêm gợi ý loại vào mã của mình. Trong phần này, bạn sẽ tìm hiểu thêm về cách thực sự kiểm tra kiểu tĩnh của mã Python

Dự án Mypy

Mypy đã được bắt đầu bởi Jukka Lehtosalo trong thời gian tiến sĩ của mình. D. học tại Cambridge khoảng năm 2012. Mypy ban đầu được hình dung là một biến thể Python với kiểu gõ động và tĩnh liền mạch. Xem các slide của Jukka từ PyCon Phần Lan 2012 để biết ví dụ về tầm nhìn ban đầu của Mypy

Hầu hết những ý tưởng ban đầu đó vẫn đóng một vai trò quan trọng trong dự án Mypy. Trên thực tế, khẩu hiệu “Gõ động và tĩnh liền mạch” vẫn hiển thị nổi bật trên trang chủ của Mypy và mô tả rõ động cơ thúc đẩy sử dụng các gợi ý kiểu trong Python

Thay đổi lớn nhất kể từ năm 2012 là Mypy không còn là một biến thể của Python. Trong các phiên bản đầu tiên, Mypy là một ngôn ngữ độc lập tương thích với Python ngoại trừ các khai báo kiểu của nó. Theo gợi ý của Guido van Rossum, Mypy đã được viết lại để sử dụng chú thích thay thế. Hôm nay Mypy là trình kiểm tra kiểu tĩnh cho mã Python thông thường

Chạy Mypy

Trước khi chạy Mypy lần đầu tiên, bạn phải cài đặt chương trình. Điều này được thực hiện dễ dàng nhất bằng cách sử dụng

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

52

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

4

Với Mypy được cài đặt, bạn có thể chạy nó như một chương trình dòng lệnh thông thường

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

42

Chạy Mypy trên tệp Python

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
914 của bạn sẽ kiểm tra lỗi loại mà không thực sự thực thi mã

Có nhiều tùy chọn có sẵn khi gõ kiểm tra mã của bạn. Vì Mypy vẫn đang được phát triển rất tích cực, các tùy chọn dòng lệnh có thể thay đổi giữa các phiên bản. Bạn nên tham khảo phần trợ giúp của Mypy để xem cài đặt nào là mặc định trên phiên bản của bạn

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

43

Ngoài ra, tài liệu dòng lệnh Mypy trực tuyến có rất nhiều thông tin

Hãy xem xét một số tùy chọn phổ biến nhất. Trước hết, nếu bạn đang sử dụng các gói của bên thứ ba không có gợi ý về loại, bạn có thể muốn tắt các cảnh báo của Mypy về những. Điều này có thể được thực hiện với tùy chọn

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
915

Ví dụ sau sử dụng Numpy để tính và in cosin của một số số

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

44

Lưu ý rằng

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
916 chỉ có trong phiên bản 1. 15 trở lên của Numpy. Chạy ví dụ này sẽ in một số số ra bàn điều khiển

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

45

Đầu ra thực tế của ví dụ này không quan trọng. Tuy nhiên, bạn nên lưu ý rằng đối số

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
917 được chú thích bằng
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
918 trên dòng 5, vì chúng tôi muốn in cosin của một dãy số đầy đủ

Bạn có thể chạy Mypy trên tệp này như bình thường

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

46

Những cảnh báo này có thể không có ý nghĩa ngay lập tức đối với bạn, nhưng bạn sẽ sớm tìm hiểu về sơ khai và đánh máy. Về cơ bản, bạn có thể đọc các cảnh báo khi Mypy nói rằng gói Numpy không chứa các gợi ý về loại

Trong hầu hết các trường hợp, các gợi ý loại bị thiếu trong các gói của bên thứ ba không phải là điều bạn muốn làm phiền, vì vậy bạn có thể tắt các tin nhắn này

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

47

Nếu bạn sử dụng tùy chọn dòng lệnh

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
919, Mypy sẽ không cố theo dõi hoặc cảnh báo về bất kỳ lần nhập nào bị thiếu. Tuy nhiên, điều này có thể hơi nặng tay vì nó cũng bỏ qua các lỗi thực tế, chẳng hạn như viết sai chính tả tên của một gói

Hai cách ít xâm phạm hơn để xử lý các gói của bên thứ ba là sử dụng nhận xét loại hoặc tệp cấu hình

Trong một ví dụ đơn giản như ví dụ trên, bạn có thể tắt cảnh báo

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
920 bằng cách thêm một nhận xét loại vào dòng chứa nội dung nhập

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

48

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
921 theo nghĩa đen bảo Mypy bỏ qua việc nhập Numpy

Nếu bạn có nhiều tệp, việc theo dõi những lần nhập nào cần bỏ qua trong tệp cấu hình có thể dễ dàng hơn. Mypy đọc một tệp có tên là

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
922 trong thư mục hiện tại nếu nó có mặt. Tệp cấu hình này phải chứa một phần có tên là
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
923 và có thể chứa các phần cụ thể của mô-đun có dạng
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
924

Tệp cấu hình sau sẽ bỏ qua gợi ý loại Numpy bị thiếu

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

49

Có nhiều tùy chọn có thể được chỉ định trong tệp cấu hình. Cũng có thể chỉ định một tệp cấu hình chung. Xem tài liệu để cho biết thêm thông tin chi tiết

Thêm sơ khai

Gợi ý loại có sẵn cho tất cả các gói trong thư viện chuẩn Python. Tuy nhiên, nếu bạn đang sử dụng các gói của bên thứ ba, bạn đã thấy rằng tình huống có thể khác

Ví dụ sau sử dụng gói Parse để thực hiện phân tích cú pháp văn bản đơn giản. Để làm theo, trước tiên bạn nên cài đặt Parse

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

00

Phân tích cú pháp có thể được sử dụng để nhận dạng các mẫu đơn giản. Đây là một chương trình nhỏ cố gắng hết sức để tìm ra tên của bạn

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

01

Luồng chính được xác định trong ba dòng cuối cùng. hỏi tên của bạn, phân tích câu trả lời và in lời chào. Gói

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
925 được gọi ở dòng 14 để cố gắng tìm tên dựa trên một trong các mẫu được liệt kê ở dòng 7-11

Chương trình có thể được sử dụng như sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

02

Lưu ý rằng mặc dù tôi trả lời

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
926, nhưng chương trình chỉ ra rằng
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
927 không phải là một phần tên của tôi

Hãy thêm một lỗi nhỏ vào chương trình và xem liệu Mypy có thể giúp chúng tôi phát hiện ra nó không. Thay đổi dòng 16 từ

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
928 thành
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
929. Điều này sẽ trả về một đối tượng
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
930 thay vì chuỗi chứa tên

Tiếp theo chạy Mypy trên chương trình

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

03

Mypy in một lỗi tương tự như lỗi bạn đã thấy trong phần trước. Nó không biết về gói

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
925. Bạn có thể thử bỏ qua việc nhập

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

04

Thật không may, bỏ qua quá trình nhập có nghĩa là Mypy không có cách nào phát hiện ra lỗi trong chương trình của chúng tôi. Một giải pháp tốt hơn là thêm các gợi ý loại vào chính gói Parse. Vì Parse là nguồn mở, bạn thực sự có thể thêm các loại vào mã nguồn và gửi yêu cầu kéo

Ngoài ra, bạn có thể thêm các loại trong tệp sơ khai. Tệp sơ khai là một tệp văn bản chứa chữ ký của các phương thức và hàm, nhưng không chứa các triển khai của chúng. Chức năng chính của chúng là thêm các gợi ý kiểu vào mã mà bạn không thể thay đổi vì lý do nào đó. Để hiển thị cách thức hoạt động của nó, chúng tôi sẽ thêm một số sơ khai cho gói Parse

Trước hết, bạn nên đặt tất cả các tệp sơ khai của mình vào trong một thư mục chung và đặt biến môi trường

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
932 để trỏ đến thư mục này. Trên Mac và Linux, bạn có thể đặt
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
932 như sau

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

05

Bạn có thể đặt biến vĩnh viễn bằng cách thêm dòng vào tệp

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
934 của mình. Trên Windows, bạn có thể nhấp vào menu bắt đầu và tìm kiếm các biến môi trường để đặt
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
932

Tiếp theo, tạo một tệp bên trong thư mục sơ khai của bạn mà bạn gọi là

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
936. Nó phải được đặt tên cho gói mà bạn đang thêm gợi ý loại, với hậu tố
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
937. Để trống tập tin này ngay bây giờ. Sau đó chạy lại Mypy

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

06

Nếu bạn đã thiết lập mọi thứ chính xác, bạn sẽ thấy thông báo lỗi mới này. Mypy sử dụng tệp

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
936 mới để tìm ra chức năng nào có sẵn trong gói
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
925. Vì tệp sơ khai trống, Mypy giả định rằng
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
940 không tồn tại và sau đó đưa ra lỗi mà bạn thấy ở trên

Ví dụ sau không thêm các loại cho toàn bộ gói

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
925. Thay vào đó, nó hiển thị gợi ý loại bạn cần thêm để Mypy nhập kiểm tra việc bạn sử dụng
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
940

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

07

Dấu chấm lửng

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
943 là một phần của tệp và phải được viết chính xác như trên. Tệp sơ khai chỉ nên chứa các gợi ý kiểu cho các biến, thuộc tính, hàm và phương thức, do đó, việc triển khai nên được bỏ qua và thay thế bằng dấu
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
943

Cuối cùng Mypy cũng có thể phát hiện ra lỗi mà chúng tôi đã giới thiệu

>>> thing = "Hello"
>>> type[thing]


>>> thing = 28.1
>>> type[thing]

08

Điều này trỏ thẳng đến dòng 16 và thực tế là chúng tôi trả về một đối tượng

>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
945 chứ không phải chuỗi tên. Đổi lại
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
929 thành
>>> if False:
..     1 + "two"  # This line never runs, so no TypeError is raised
.. else:
..     1 + 2
...
3

>>> 1 + "two"  # Now this is type checked, and a TypeError is raised
TypeError: unsupported operand type[s] for +: 'int' and 'str'
928, chạy lại Mypy thấy sướng

đánh máy

Bạn đã biết cách sử dụng sơ khai để thêm gợi ý loại mà không thay đổi chính mã nguồn. Trong phần trước, chúng tôi đã thêm một số gợi ý loại vào gói Parse của bên thứ ba. Bây giờ, sẽ không hiệu quả lắm nếu mọi người cần tạo các tệp sơ khai của riêng họ cho tất cả các gói của bên thứ ba mà họ đang sử dụng

Typeshed là kho lưu trữ Github chứa các gợi ý về kiểu cho thư viện chuẩn Python, cũng như nhiều gói của bên thứ ba. Đã đánh máy đi kèm với Mypy, vì vậy nếu bạn đang sử dụng gói đã có các gợi ý về loại được xác định trong Typeshed, thì việc kiểm tra kiểu sẽ chỉ hoạt động

Bạn cũng có thể đóng góp các gợi ý về kiểu chữ cho Typeshed. Tuy nhiên, trước tiên hãy đảm bảo xin phép chủ sở hữu gói, đặc biệt là vì họ có thể đang làm việc để thêm gợi ý loại vào chính mã nguồn—đây là cách tiếp cận ưa thích

Trình kiểm tra loại tĩnh khác

Trong hướng dẫn này, chúng tôi chủ yếu tập trung vào kiểm tra kiểu bằng Mypy. Tuy nhiên, có các trình kiểm tra kiểu tĩnh khác trong hệ sinh thái Python

Trình chỉnh sửa PyCharm đi kèm với trình kiểm tra loại riêng đi kèm. Nếu bạn đang sử dụng PyCharm để viết mã Python của mình, nó sẽ tự động được kiểm tra loại

Facebook đã phát triển Pyre. Một trong những mục tiêu đã nêu của nó là nhanh chóng và hiệu quả. Mặc dù có một số khác biệt, các chức năng của Pyre hầu như tương tự như Mypy. Xem tài liệu nếu bạn muốn dùng thử Pyre

Hơn nữa, Google đã tạo Pytype. Trình kiểm tra loại này cũng hoạt động gần giống như Mypy. Ngoài việc kiểm tra mã được chú thích, Pytype còn có một số hỗ trợ để chạy kiểm tra loại trên mã không được chú thích và thậm chí tự động thêm chú thích vào mã. Xem tài liệu bắt đầu nhanh để biết thêm thông tin

Sử dụng các loại trong thời gian chạy

Lưu ý cuối cùng, bạn cũng có thể sử dụng các gợi ý loại trong thời gian chạy trong quá trình thực thi chương trình Python của mình. Kiểm tra loại thời gian chạy có thể sẽ không bao giờ được hỗ trợ nguyên bản trong Python

Tuy nhiên, gợi ý loại có sẵn trong thời gian chạy trong từ điển

String thing;
thing = "Hello";
10 và bạn có thể sử dụng chúng để kiểm tra loại nếu muốn. Trước khi bạn chạy và viết gói của riêng mình để thực thi các loại, bạn nên biết rằng đã có một số gói làm việc này cho bạn. Hãy xem Enforce, Pydantic hoặc Pytypes để biết một số ví dụ

Một cách sử dụng khác của gợi ý loại là để dịch mã Python của bạn sang C và biên dịch nó để tối ưu hóa. Dự án Cython phổ biến sử dụng ngôn ngữ C/Python lai để viết mã Python được nhập tĩnh. Tuy nhiên, kể từ phiên bản 0. 27 Cython cũng đã hỗ trợ các chú thích kiểu. Gần đây, dự án Mypyc đã có sẵn. Mặc dù chưa sẵn sàng để sử dụng chung, nhưng nó có thể biên dịch một số loại mã Python được chú thích thành các tiện ích mở rộng C

Phần kết luận

Gõ gợi ý trong Python là một tính năng rất hữu ích mà bạn có thể vui vẻ sống mà không cần. Gợi ý nhập không giúp bạn có khả năng viết bất kỳ mã nào mà bạn không thể viết nếu không sử dụng gợi ý nhập. Thay vào đó, sử dụng các gợi ý kiểu giúp bạn dễ dàng suy luận về mã hơn, tìm ra các lỗi tinh vi và duy trì một kiến ​​trúc rõ ràng

Trong hướng dẫn này, bạn đã học cách gợi ý kiểu hoạt động trong Python và cách gõ dần dần giúp kiểm tra kiểu trong Python linh hoạt hơn so với nhiều ngôn ngữ khác. Bạn đã thấy một số ưu và nhược điểm của việc sử dụng gợi ý kiểu và cách chúng có thể được thêm vào mã bằng cách sử dụng chú thích hoặc chú thích kiểu. Cuối cùng, bạn đã thấy nhiều kiểu khác nhau mà Python hỗ trợ, cũng như cách thực hiện kiểm tra kiểu tĩnh

Có nhiều tài nguyên để tìm hiểu thêm về kiểm tra kiểu tĩnh trong Python. PEP 483 và PEP 484 cung cấp nhiều thông tin cơ bản về cách triển khai kiểm tra kiểu trong Python. Tài liệu Mypy có phần tham khảo tuyệt vời nêu chi tiết tất cả các loại khác nhau có sẵn

Đánh dấu là đã hoàn thành

Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Kiểm tra loại Python

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Gửi cho tôi thủ thuật Python »

Giới thiệu về Geir Arne Hjelle

Geir Arne là một Pythonista cuồng nhiệt và là thành viên của nhóm hướng dẫn Real Python

» Thông tin thêm về Geir Arne

Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Aldren

Brad

Joanna

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bậc thầy Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng các chuyên gia Pythonistas

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Gõ nghĩa là gì trong Python?

Python vừa là ngôn ngữ được gõ mạnh vừa là ngôn ngữ được gõ động. Nhập mạnh có nghĩa là các biến có một loại và loại đó quan trọng khi thực hiện các thao tác trên một biến . Nhập động có nghĩa là loại biến chỉ được xác định trong thời gian chạy.

Loại nào có thể gọi được?

Loại có thể gọi là loại mà thao tác IVOKE [được sử dụng bởi, e. g. , tiêu chuẩn. chức năng, tiêu chuẩn. ràng buộc, và tiêu chuẩn. chủ đề. chủ đề] được áp dụng . Thao tác IVOKE có thể được thực hiện rõ ràng bằng cách sử dụng hàm thư viện std. gọi.

Mục đích của hàm type[] là gì?

Hàm type[] được sử dụng để lấy loại đối tượng . Khi một đối số duy nhất được chuyển đến hàm type[], nó sẽ trả về kiểu của đối tượng. Giá trị của nó giống như đối tượng. __class__ biến thể hiện.

Python xử lý việc gõ như thế nào?

Python sẽ luôn là ngôn ngữ được nhập động . Tuy nhiên, PEP 484 đã giới thiệu các gợi ý về kiểu, cho phép thực hiện kiểm tra kiểu tĩnh của mã Python. Không giống như cách các loại hoạt động trong hầu hết các ngôn ngữ được nhập tĩnh khác, bản thân các gợi ý nhập không khiến Python thực thi các loại.

Chủ Đề