Hướng dẫn what is type checking in python? - kiểm tra kiểu trong python là gì?

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn về sự hiểu biết của bạn: Kiểm tra loại Python This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Python Type Checking

Show

Trong hướng dẫn này, bạn sẽ xem xét kiểm tra loại Python. Theo truyền thống, các loại đã được xử lý bởi người phiên dịch Python một cách linh hoạt nhưng ngầm. Các phiên bản gần đây của Python cho phép bạn chỉ định các gợi ý loại rõ ràng có thể được sử dụng bởi các công cụ khác nhau để 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à loại gợi ý
  • Thêm các loại tĩnh vào mã, cả mã của bạn và mã của những người khác
  • Chạy một trình kiểm tra loại 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 mặt đất. Nếu bạn muốn có một cái nhìn nhanh chóng về cách các gợi ý loại hoạt động trong Python và xem liệu kiểm tra loại 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ẽ cung cấp cho bạn cách kiểm tra loại hoạt động và đề xuất về khi nó sẽ hữu ích.

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 loại đối tượng mà nó có thể hoạt động và cách xử lý các loại đó. Chẳng hạn, một hệ thống loại có thể xác định một loại số, với

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
6 là một ví dụ về một đối tượng thuộc loại số.

Gõ động

Python là một ngôn ngữ được đánh máy động. Điều này có nghĩa là trình thông dịch Python chỉ kiểm tra loại khi mã chạy và loại biến được phép thay đổi trong suốt vòng đời của nó. Các ví dụ giả sau đây chứng minh rằng Python có 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, chi nhánh

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
7 không bao giờ chạy để nó không bao giờ được kiểm tra. Ví dụ thứ hai cho thấy rằng khi
 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
7 được đánh giá, nó sẽ tăng
 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
9 vì bạn có thể thêm một số nguyên và một chuỗi trong Python.

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

>>>

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

>>> 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, chi nhánh 1# headlines.py 2 3def headline(text: str, align: bool = True) -> str: 4 if align: 5 return f"{text.title()}\n{'-' * len(text)}" 6 else: 7 return f" {text.title()} ".center(50, "o") 8 9print(headline("python type checking")) 10print(headline("use mypy", align="center")) 7 không bao giờ chạy để nó không bao giờ được kiểm tra. Ví dụ thứ hai cho thấy rằng khi 1# headlines.py 2 3def headline(text: str, align: bool = True) -> str: 4 if align: 5 return f"{text.title()}\n{'-' * len(text)}" 6 else: 7 return f" {text.title()} ".center(50, "o") 8 9print(headline("python type checking")) 10print(headline("use mypy", align="center")) 7 được đánh giá, nó sẽ tăng 1# headlines.py 2 3def headline(text: str, align: bool = True) -> str: 4 if align: 5 return f"{text.title()}\n{'-' * len(text)}" 6 else: 7 return f" {text.title()} ".center(50, "o") 8 9print(headline("python type checking")) 10print(headline("use mypy", align="center")) 9 vì bạn có thể thêm một số nguyên và một chuỗi trong Python.

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

00 Trả về loại đối tượng. Các ví dụ này xác nhận rằng loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

01 được phép thay đổi và Python chính xác thông tin loại khi nó thay đổi.

Gõ tĩnh

String thing;
thing = "Hello";

Đối diện của 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. Ví dụ, trong hầu hết các ngôn ngữ được gõ tĩ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 việc gõ tĩnh, các biến thường không được phép thay đổi các loại, mặc dù các cơ chế để tạo ra một biến thành một loại khác có thể tồn tại.

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

Dòng đầu tiên tuyên bố rằng tên biến >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 01 được liên kết với loại >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 03 tại thời điểm biên dịch. Tên không bao giờ có thể được bật lại cho một loại khác. Trong dòng thứ hai, >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 01 được gán một 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) 03. Chẳng hạn, nếu sau này bạn nói >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 06, trình biên dịch sẽ gây ra lỗi vì các loại không tương thích.

Python sẽ luôn luôn là một ngôn ngữ được đánh máy động. Tuy nhiên, PEP 484 đã giới thiệu các gợi ý loại, điều này cũng có thể thực hiện kiểm tra loại 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 gõ tĩnh khác, bản thân các gợi ý của chúng tôi đã khiến Python thực thi các loại. Như tên nói, loại gợi ý chỉ đề xuất các loại. Có các công cụ khác, mà bạn sẽ thấy sau đó, thực hiện kiểm tra loại tĩnh bằng cách sử dụng gợi ý loại.

Gõ vịt

>>>

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022

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

def len(obj):
    return obj.__len__()

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

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
7 không bao giờ chạy để nó không bao giờ được kiểm tra. Ví dụ thứ hai cho thấy rằng khi
 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
7 được đánh giá, nó sẽ tăng
 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
9 vì bạn có thể thêm một số nguyên và một chuỗi trong Python.

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

Các loại xin chào

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 đây biến một chuỗi văn bản thành một tiêu đề bằng cách thêm vốn hóa thích hợp và một dòng trang trí:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

19 thành
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

20, bạn có thể có tiêu đề được tập trung với một dòng xung quanh là
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

21:

>>>

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo

Đó là thời gian cho gợi ý loại đầu tiên của chúng tôi! Để thêm thông tin về các loại 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:

def headline(text: str, align: bool = True) -> str:
    ...

Cú pháp

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

22 nói rằng đối số
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

23 phải thuộc loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15. Tương tự, đối số
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

19 tùy chọn phải có loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26 với giá trị mặc định
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

27. Cuối cùng, ký hiệu
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

28 chỉ định rằng
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

29 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 các đại phân, nghĩa là không có không gian trước và một không gian sau một dấu hai chấm:
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    22.
  • Sử dụng các khoảng trống xung quanh dấu hiệu
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    31 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)
    
    
    32.
  • Sử dụng không gian xung quanh mũi tên
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    33:
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    34.

Thêm các 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. Chẳng hạn, nếu chúng ta sử dụng một loại sai cho đối số (thừa nhận được đặt tên xấu)

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

19, mã vẫn chạy mà không có bất kỳ vấn đề hoặc cảnh báo nào:

>>>

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------

Đó là thời gian cho gợi ý loại đầu tiên của chúng tôi! Để thêm thông tin về các loại 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:

Cú pháp

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

22 nói rằng đối số
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

23 phải thuộc loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15. Tương tự, đối số
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

19 tùy chọn phải có loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26 với giá trị mặc định
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

27. Cuối cùng, ký hiệu
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

28 chỉ định rằng
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

Hướng dẫn what is type checking in python? - kiểm tra kiểu trong python là gì?

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

Sử dụng các quy tắc bình thường cho các đại phân, nghĩa là không có không gian trước và một không gian sau một dấu hai chấm:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

22.

Sử dụng các khoảng trống xung quanh dấu hiệu

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

32.

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))

Sử dụng không gian xung quanh mũi tên

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

33:
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

34.

Thêm các 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. Chẳng hạn, nếu chúng ta sử dụng một loại sai cho đối số (thừa nhận được đặt tên xấu)

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

19, mã vẫn chạy mà không có bất kỳ vấn đề hoặc cảnh báo nào:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

0

Để bắt loại lỗi này, bạn có thể sử dụng trình kiểm tra loại tĩnh. Đó 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 trong trình soạn thảo của bạn. Ví dụ, Pycharm ngay lập tức đưa ra cảnh báo cho bạn:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

1

Công cụ phổ biến nhất để kiểm tra loại là mypy mặc dù. Bạn sẽ nhận được một 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 sau này.

Nếu bạn không có MyPy trên hệ thống của mình, bạn có thể cài đặt nó bằng

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

36:

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

37:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

3

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

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

Dựa trên các gợi ý loại, MyPy có thể cho chúng tôi biết rằng chúng tôi đang sử dụng sai loại trên dòng 10.catch certain errors. Other advantages include:

  • Để 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)
    
    
    19 mà bạn đang truyền. Bạn cũng có thể đổi tên cờ
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    19 thành một cái gì đó ít gây nhầm lẫn hơn:document your code. Traditionally, you would use docstrings if you wanted to document the expected types of a function’s arguments. This works, but as there is no standard for docstrings (despite PEP 257 they can’t be easily used for automatic checks.

  • Tại đây, bạn đã thay đổi

    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    19 thành
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    42 và sử dụng chính xác giá trị boolean cho
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    42 khi gọi
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    29. Mã hiện vượt qua MyPy:improve IDEs and linters. They make it much easier to statically reason about your code. This in turn allows IDEs to offer better code completion and similar features. With the type annotation, PyCharm knows that
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    23 is a string, and can give specific suggestions based on this:

    Hướng dẫn what is type checking in python? - kiểm tra kiểu trong python là gì?
  • >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    2build and maintain a cleaner architecture. The act of writing type hints forces you to think about the types in your program. While the dynamic nature of Python is one of its great assets, being conscious about relying on duck typing, overloaded methods, or multiple return types is a good thing.

Thông báo thành công xác nhận không có lỗi loại được phát hiện. Các phiên bản cũ hơn của MyPy được sử dụng để chỉ ra điều này bằng cách hiển thị không có đầ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:

  • Tiêu đề đầu tiên được căn chỉnh bên trái, trong khi cái thứ hai được tập trung.take developer time and effort to add. Even though it probably pays off in spending less time debugging, you will spend more time entering code.

  • Ưu và nhược điểmwork best in modern Pythons. Annotations were introduced in Python 3.0, and it’s possible to use type comments in Python 2.7. Still, improvements like variable annotations and postponed evaluation of type hints mean that you’ll have a better experience doing type checks using Python 3.6 or even Python 3.7.

  • Loại 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)
    
    
    46, thời gian nhập có thể có ý nghĩa, đặc biệt là trong các tập lệnh ngắn.introduce a slight penalty in startup time. If you need to use the
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    46 module the import time may be significant, especially in short scripts.

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

Để có đượ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)

48 phải là một tệp trống, trong khi
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

49 nên chứa dòng sau:

Trên Linux, nó khá dễ dàng để kiểm tra thời gian nhập khẩu

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 sử dụng tiện ích
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

51:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

4

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

52 mất khoảng 45 mili giây. Tất nhiên đây không phải là tất cả thời gian dành cho việc nhập
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46. Một số trong số này là chi phí trong việc bắt đầu 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)

5

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 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 là khởi động nhanh hơn. Hãy để xem nếu kết quả khác nhau:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

6

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 khẩu

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

Sử dụng

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

56

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)

56 trong thư viện tiêu 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)

56 cho các thời gian trên. Tuy nhiên,
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

56 đấu tranh để nhập khẩu thời gian một cách đáng tin cậy vì Python chỉ thông minh về việc 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)

7

Mặc dù 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 số lượng

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

51 được đo! Những gì
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

56 thực sự đã thực hiện là chạy tuyên bố
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

62 30 triệu lần, với Python thực sự chỉ nhập
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 một lần.

Để có được kết quả hợp lý, bạn có thể nói

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

56 chỉ chạy một lần:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

8

Những kết quả này ở cùng quy mô với kết quả từ

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 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ể sẽ không phải là một vấn đề.

Tùy chọn

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

67 mới

Trong Python 3.7, cũng có một tùy chọn dòng lệnh mới có thể được sử dụng để tìm ra số thời gian nhập khẩu. Sử dụng

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

68, bạn sẽ nhận được một báo cáo về tất cả các nhập khẩu được thực hiện:

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

9

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

70 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

71 mà
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 phụ thuộc vào.

Vì vậy, bạn nên sử dụng kiểm tra loại tĩnh trong mã của riêng bạn? Chà, nó không phải là một câu hỏi tất cả hoặc không có gì. 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ị bỏ qua bởi trình kiểm tra loại tĩnh. 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ó thêm giá trị cho bạn.

Nhìn vào các danh sách trên của ưu và nhược điểm mà bạn sẽ nhận thấy rằng việc thêm các loại sẽ không có tác dụng đối với 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 có nghĩa là làm cho cuộc sống của bạn như một nhà phát triển tốt hơn và thuận tiện hơn.

Một vài quy tắc về việc có nên thêm các loại vào dự án của bạn là:

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

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

  • Trong các thư viện sẽ được sử dụng bởi những người khác, đặc biệt là các thư viện được xuất bản trên PYPI, gõ gợi ý thêm 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 để tự kiểm tra đúng. Để biết các ví dụ về các dự án sử dụng gợi ý loại, xem

    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    73,
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    74, đầu đọc Python thực sự của chúng tôi và chính MyPy.

  • Trong các dự án lớn hơn, các gợi ý loại 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 trong các dự án mà bạn hợp tác với người khác.

Trong bài viết xuất sắc của mình, trạng thái của các gợi ý loại trong Python Bernátbor khuyến nghị rằng nên sử dụng gợi ý loại của 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õ gợi ý đóng một vai trò tương tự như các bài kiểm tra trong mã của bạn: chúng giúp bạn như một nhà phát triển viết mã tốt hơn.type hints should be used whenever unit tests are worth writing.” Indeed, type hints play a similar role as tests in your code: they help you as a developer write better code.

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

Trong phần còn lại của hướng dẫn này, chúng tôi sẽ đi sâu vào chi tiết hơn về hệ thống loại Python, bao gồm cả cách bạn chạy Trình kiểm tra loại 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ó gợi ý loại và cách bạn Sử dụng chú thích trong thời gian chạy.

Chú thích

Các chú thích được giới thiệu trong Python 3.0, ban đầu không có mục đích cụ thể nào. 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ố chức năng và trả về các giá trị.

Nhiều năm sau, PEP 484 đã xác định cách thêm gợi ý loại 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ự án kiểu mẫu. Cách chính để thêm gợi ý loại là sử dụng chú thích. Vì kiểm tra loại ngày càng trở nên phổ biến hơ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 ý loại.

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

Chú thích chức năng

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

String thing;
thing = "Hello";
0

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

75, trong khi loại trả về được chú thích bằng
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

76. 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 các chú thích vào một hàm tính toán chu vi của một vòng tròn:

String thing;
thing = "Hello";
1

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)

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

>>>

String thing;
thing = "Hello";
2

Đôi khi bạn có thể bị nhầm lẫn bởi cách MyPy đang diễn giải 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)

78 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

79. Bạn có thể thêm những thứ này vào mã của mình trước khi chạy MyPy và MyPy sẽ báo cáo một cách nghiêm túc những loại đã suy ra. Ví dụ, lưu mã sau vào
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

80:

String thing;
thing = "Hello";
3

Tiếp theo, chạy mã này qua MyPy:

String thing;
thing = "Hello";
4

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)

81 tích hợp, cũng như các biến cục bộ của chúng tôi
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

82 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

83.

Nếu MyPy nói rằng tên của

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

79 có sẵn trong phiên bản MyPy 0.610 trở lên.

Chú thích biến

Trong định nghĩa của

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

86 trong phần trước, bạn chỉ chú thích các đối số và giá trị trả về. Bạn đã không thêm bất kỳ chú thích nào bên trong cơ thể chức năng. 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 thay đổi được xác định trong PEP 526 và được giới thiệu trong Python 3.6. Cú pháp giống như đối với các chú thích đối số chức năng:

String thing;
thing = "Hello";
5

Biến

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

87 đã được chú thích bằng gợi ý loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88.

Chú thích của các biến được lưu trữ trong từ điển cấp độ mô -đun

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

89:

>>>

String thing;
thing = "Hello";
6

Đôi khi bạn có thể bị nhầm lẫn bởi cách MyPy đang diễn giải 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)

78 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

79. Bạn có thể thêm những thứ này vào mã của mình trước khi chạy MyPy và MyPy sẽ báo cáo một cách nghiêm túc những loại đã suy ra. Ví dụ, lưu mã sau vào
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

80:

>>>

String thing;
thing = "Hello";
7

Đôi khi bạn có thể bị nhầm lẫn bởi cách MyPy đang diễn giải 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)

78 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

79. Bạn có thể thêm những thứ này vào mã của mình trước khi chạy MyPy và MyPy sẽ báo cáo một cách nghiêm túc những loại đã suy ra. Ví dụ, lưu mã sau vào
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

80:

Tiếp theo, chạy mã này qua MyPy:

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)

81 tích hợp, cũng như các biến cục bộ của chúng tôi
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

82 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

83.

Nếu MyPy nói rằng tên của

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

79 có sẵn trong phiên bản MyPy 0.610 trở lên.

  • Chú thích biến
  • Trong định nghĩa của
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    86 trong phần trước, bạn chỉ chú thích các đối số và giá trị trả về. Bạn đã không thêm bất kỳ chú thích nào bên trong cơ thể chức năng. 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 thay đổi được xác định trong PEP 526 và được giới thiệu trong Python 3.6. Cú pháp giống như đối với các chú thích đối số chức năng:
  • Biến
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    87 đã được chú thích bằng gợi ý loại
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    88.

Chú thích của các biến được lưu trữ trong từ điển cấp độ mô -đun

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

89:

Bạn đã cho phép chú thích một biến mà không cho nó một giá trị. Điều này thêm chú thích cho từ điển >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 89, trong khi biến vẫn chưa được xác định:

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

91, nên tên
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

91 chưa được xác định.

String thing;
thing = "Hello";
8

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)

15,
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26 trong các gợi ý loại của bạn. Hệ thống loại Python khá mạnh mẽ 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ợp lý bản chất đánh máy vịt năng động Python.

String thing;
thing = "Hello";
9

Trong phần này, bạn sẽ tìm hiểu thêm về hệ thống loại này, đồng thời 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 các bí danh làm cho mã dễ đọc hơn

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

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15,
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26, việc thêm gợi ý loại cũng dễ như sử dụng loại chính:

>>>

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
0

Với các loại tổng hợp, bạn được phép làm như vậy:

>>>

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
1

Với các loại tổng hợp, bạn được phép làm như vậy:

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

String thing;
thing = "Hello";
05,
String thing;
thing = "Hello";
06 và
String thing;
thing = "Hello";
07 sẽ là gì? Trong trường hợp cụ thể này, bạn có thể thấy rằng chúng lần lượt là
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15,
String thing;
thing = "Hello";
09 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26. Tuy nhiên, loại gợi ý bản thân không cung cấp thông tin về điều này.

>>>

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
2

Với các loại tổng hợp, bạn được phép làm như vậy:

  • Tuy nhiên, điều này không thực sự kể toàn bộ câu chuyện. Các loại của
    String thing;
    thing = "Hello";
    
    05,
    String thing;
    thing = "Hello";
    
    06 và
    String thing;
    thing = "Hello";
    
    07 sẽ là gì? Trong trường hợp cụ thể này, bạn có thể thấy rằng chúng lần lượt là
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    15,
    String thing;
    thing = "Hello";
    
    09 và
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    26. Tuy nhiên, loại gợi ý bản thân không cung cấp thông tin về điều này.
    is a list of strings
  • 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)
    
    
    46. 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:
    is a 3-tuple consisting of three integers
  • Lưu ý rằng mỗi loại này bắt đầu bằng một chữ cái viết hoa và tất cả chúng đều sử dụng dấu ngoặc vuông để xác định các loại vật phẩm: is a dictionary mapping strings to Boolean values

String thing;
thing = "Hello";
12 là danh sách các chuỗi

String thing;
thing = "Hello";
13 là 3-tuple bao gồm ba số nguyên

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
3

String thing;
thing = "Hello";
14 là một chuỗi ánh xạ từ điển để boolean giá trị

Mô -đun

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 chứa nhiều loại tổng hợp hơn, bao gồm
String thing;
thing = "Hello";
16,
String thing;
thing = "Hello";
17,
String thing;
thing = "Hello";
18,
String thing;
thing = "Hello";
19 và
String thing;
thing = "Hello";
20. 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.

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
4

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

String thing;
thing = "Hello";
21, vì vậy loại bài của thẻ trở thành
String thing;
thing = "Hello";
22. Do đó, bạn có thể chú thích
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

96 như sau:

Ngoài giá trị trả về, bạn cũng đã thêm loại >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 26 vào đối số String thing; thing = "Hello"; 25 tùy chọn.

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 liệu đó là danh sách hay một tuple. Trong những trường hợp, bạn nên sử dụng

String thing;
thing = "Hello";
26 khi chú thích đối số chức năng:

Sử dụng

String thing;
thing = "Hello";
27 là một ví dụ về việc sử dụng gõ vịt. A
String thing;
thing = "Hello";
27 là bất cứ điều gì hỗ trợ
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

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

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
5

Loại bí danh

Các gợi ý loại có thể trở nên khá xiên khi làm việc với các loại lồng nhau như bộ bài. Bạn có thể cần phải nhìn chằm chằm vào

String thing;
thing = "Hello";
22 một chút trước khi tìm ra rằng nó phù hợp với đại diện của chúng tôi về một bộ bài của chúng tôi.

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
6

Bây giờ hãy xem xét cách bạn sẽ chú thích

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

97:

Đó chỉ là khủng khiếp!

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
7

Hãy nhớ lại rằng các chú thích loại là biểu thức python thường xuyên. Điều đó có nghĩa là bạn có thể xác định các bí danh loại của riêng bạn bằng cách gán chúng cho các biến mới. Ví dụ, bạn có thể tạo các bí danh

String thing;
thing = "Hello";
33 và
String thing;
thing = "Hello";
34:

>>>

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
8

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

Sử dụng các bí danh này, các chú thích của >>> thing = "Hello" >>> type(thing) >>> thing = 28.1 >>> type(thing) 97 trở nên dễ đọc hơn nhiều:

Loại bí danh là tuyệt vời để 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:

>>>

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
9

Lưu ý rằng khi in

String thing;
thing = "Hello";
34, nó cho thấy nó là một bí danh cho danh sách các chuỗi 2 chuỗi.

def len(obj):
    return obj.__len__()
0

Các chức năng không có giá trị trả về

def len(obj):
    return obj.__len__()
1

Bạn có thể biết rằng các chức năng mà không có sự trở lại rõ ràng vẫn trả về

String thing;
thing = "Hello";
39:

def len(obj):
    return obj.__len__()
2

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

String thing;
thing = "Hello";
39 cũng như loại trả lại:

def len(obj):
    return obj.__len__()
3

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

def len(obj):
    return obj.__len__()
4

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

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:

Như 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 để 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";
41:

def len(obj):
    return obj.__len__()
5

String thing;
thing = "Hello";
42 luôn làm tăng một ngoại lệ, nó sẽ không bao giờ quay trở lại đúng.

def len(obj):
    return obj.__len__()
6

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

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

String thing;
thing = "Hello";
44 hoạt động cho cả danh sách tên và danh sách thẻ (và bất kỳ chuỗi nào khác cho vấn đề đó). Một cách để thêm gợi ý loại cho điều này sẽ là như sau:

def len(obj):
    return obj.__len__()
7

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

String thing;
thing = "Hello";
53 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";
44 sẽ trả về một mục như vậy. Thật không may, điều này không hữu ích. Xem xét ví dụ sau:

def len(obj):
    return obj.__len__()
8

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

String thing;
thing = "Hello";
12 là danh sách các chuỗi, thông tin đó bị mất sau cuộc gọi đến
String thing;
thing = "Hello";
44 vì sử dụng loại
String thing;
thing = "Hello";
51:

def len(obj):
    return obj.__len__()
9

Bạn sẽ thấy một cách tốt hơn trong thời gian ngắn. Mặc dù vậy, trước tiên, hãy để có một cái nhìn lý thuyết hơn về hệ thống loại Python và vai trò đặc biệt ____251 đóng.

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ỉ làm trầy xước bề mặt của lý thuyết làm nền tảng cho các gợi ý 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 bỏ qua phần tiếp theo.

Phân nhóm

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

String thing;
thing = "Hello";
59 là một loại phụ của
String thing;
thing = "Hello";
60 nếu hai điều kiện sau đây giữ:subtypes. Formally, we say that a type
String thing;
thing = "Hello";
59 is a subtype of
String thing;
thing = "Hello";
60 if the following two conditions hold:

  • Mỗi giá trị từ
    String thing;
    thing = "Hello";
    
    59 cũng nằm trong tập hợp các giá trị của loại
    String thing;
    thing = "Hello";
    
    60.
  • Mọi hàm từ loại
    String thing;
    thing = "Hello";
    
    60 cũng nằm trong tập hợp các hàm của loại
    String thing;
    thing = "Hello";
    
    59.

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

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

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

String thing;
thing = "Hello";
69 và
String thing;
thing = "Hello";
70. Loại
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26 chỉ lấy hai giá trị. Thông thường chúng được biểu thị
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

27 và
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

20, nhưng những cái tên này chỉ là bí danh cho các giá trị số nguyên
String thing;
thing = "Hello";
74 và
String thing;
thing = "Hello";
75, tương ứng:

>>>

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
0

Vì 0 và 1 đều là số nguyên, điều kiện đầu tiên giữ. Ở trên bạn có thể thấy rằng booleans có thể được thêm vào với nhau, nhưng chúng cũng có thể làm bất cứ điều gì khác 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)

26 là một kiểu con của
String thing;
thing = "Hello";
09.

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à SuperType của nó. Chẳng hạn, loại mã sau kiểm tra đúng:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
1

Các kiểu con có phần liên quan đến các lớp con. Trong 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)

26 là một kiểu con của
String thing;
thing = "Hello";
09 vì
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26 là một lớp con của
String thing;
thing = "Hello";
09. Tuy nhiên, cũng có các kiểu con không tương ứng với các lớp con. Ví dụ
String thing;
thing = "Hello";
09 là một phân nhóm của
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88, nhưng
String thing;
thing = "Hello";
09 không phải là một lớp con của
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88.

Hiệp phương sai, trái ngược và bất biến

Điều gì xảy ra khi bạn sử dụng các kiểu con bên trong các loại tổng hợp? Chẳng hạn,

String thing;
thing = "Hello";
86 có phải là một kiểu con của
String thing;
thing = "Hello";
87 không? Câu trả lời phụ thuộc vào loại tổng hợp, và liệu loại đó là hiệp phương sai, trái ngược hay bất biến. Điều này trở nên nhanh chóng về kỹ thuật, vì vậy, hãy để chỉ đưa ra một vài ví dụ:

  • String thing;
    thing = "Hello";
    
    88 là hiệp phương sai. Điều này có nghĩa là nó bảo tồn hệ thống phân cấp loại của các loại mục của nó:
    String thing;
    thing = "Hello";
    
    86 là một kiểu con của
    String thing;
    thing = "Hello";
    
    87 vì
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    26 là một kiểu con của
    String thing;
    thing = "Hello";
    
    09.

  • String thing;
    thing = "Hello";
    
    93 là bất biến. Các loại 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
    String thing;
    thing = "Hello";
    
    94 là các giá trị của
    String thing;
    thing = "Hello";
    
    95, bạn có thể nối một
    String thing;
    thing = "Hello";
    
    09 lên
    String thing;
    thing = "Hello";
    
    95 và không phải
    String thing;
    thing = "Hello";
    
    94. Nói cách khác, điều kiện thứ hai cho các kiểu con không giữ và
    String thing;
    thing = "Hello";
    
    94 không phải là một kiểu con của
    String thing;
    thing = "Hello";
    
    95.

  • >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    01 là trái ngược trong các lập luận của nó. Điều này có nghĩa là nó đảo ngược hệ thống phân cấp loại. Bạn sẽ thấy cách
    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    01 hoạt động sau này, nhưng bây giờ hãy nghĩ về
    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    03 như là một hàm với đối số duy nhất của nó là loại
    String thing;
    thing = "Hello";
    
    59. Một ví dụ về
    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    05 là hàm
    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    06 được xác định ở trên. Bị ràng buộc có nghĩa là nếu một hàm hoạt động trên
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    26 được mong đợi, thì một hàm hoạt động trên
    String thing;
    thing = "Hello";
    
    09 sẽ được chấp nhận.

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

Gõ dần dần và các loại nhất quán

Trước đó, chúng tôi đã đề cập rằng Python hỗ trợ gõ dần dần, nơi bạn có thể dần dần thêm gợi ý loại vào mã Python của mình. Gõ dần dần về cơ bản được thực hiện theo loại

String thing;
thing = "Hello";
51.

Bằng cách nào đó

String thing;
thing = "Hello";
51 nằm ở cả trên cùng và ở dưới cùng của phân cấp loại của các phân nhóm. Bất kỳ loại nào đều hoạt động như thể nó là một loại phụ của
String thing;
thing = "Hello";
51 và
String thing;
thing = "Hello";
51 hoạt động như thể nó là một loại phụ của bất kỳ loại nào khác. Nhìn vào định nghĩa của các phân nhóm ở trên điều này là không thực sự có thể. Thay vào đó chúng tôi nói về các loại nhất quán.consistent types.

Loại

String thing;
thing = "Hello";
59 phù hợp với loại
String thing;
thing = "Hello";
60 nếu
String thing;
thing = "Hello";
59 là một kiểu con của
String thing;
thing = "Hello";
60 hoặc
String thing;
thing = "Hello";
59 hoặc
String thing;
thing = "Hello";
60 là
String thing;
thing = "Hello";
51.

Trình kiểm tra loại chỉ phàn nàn về các loại không nhất quán. Do đó, việc thực hiện là bạn sẽ không bao giờ thấy các lỗi loại phát sinh từ loại

String thing;
thing = "Hello";
51.

Điều này có nghĩa là bạn có thể sử dụng

String thing;
thing = "Hello";
51 để quay trở lại gõ động một cách rõ ràng, mô tả các loại quá phức tạp để mô tả trong hệ thống loại Python hoặc mô tả các mục trong các loại tổng hợp. Chẳng hạn, một từ điển với các khóa chuỗi có thể lấy bất kỳ loại nào vì giá trị của nó có thể được chú thích
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
22.

Tuy nhiên, hãy nhớ rằng, nếu bạn sử dụng

String thing;
thing = "Hello";
51, trình kiểm tra loại tĩnh sẽ không thực hiện bất kỳ loại kiểm tra nào.

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

Hãy để trở lại với các ví dụ thực tế của chúng tôi. Hãy nhớ lại rằng bạn đang cố gắng chú thích chức năng

String thing;
thing = "Hello";
44 chung:

def len(obj):
    return obj.__len__()
7

Vấn đề với việc sử dụng

String thing;
thing = "Hello";
51 là bạn không cần phải mất thông tin loại. Bạn biết rằng nếu bạn chuyển một danh sách các chuỗi cho
String thing;
thing = "Hello";
44, nó sẽ trả về một chuỗi. Dưới đây bạn sẽ thấy cách diễn đạt điều này bằng cách sử dụng các biến loại, cũng như cách làm việc với:

  • Các loại vịt và giao thức
  • Đối số với
    String thing;
    thing = "Hello";
    
    39 làm giá trị mặc định
  • Phương pháp lớp
  • Loại lớp học của riêng bạn
  • Số lượng đối số biến đổi

Loại biến

Một biến loại là một biến đặc biệt có thể đảm nhận bất kỳ loại nào, tùy thuộc vào tình huống.

Hãy để tạo ra một biến loại sẽ đóng gói hiệu quả hành vi của

String thing;
thing = "Hello";
44:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
3

Một biến loại phải được xác định bằng cách sử dụng

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
29 từ mô -đun
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46. Khi được sử dụng, một biến loại phạm vi trên tất cả các loại có thể và lấy loại cụ thể nhất có thể. Trong ví dụ,
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
31 hiện là
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
4

Xem xét một vài ví dụ khác:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
5

Hai ví dụ đầu tiên nên có loại

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15 và
String thing;
thing = "Hello";
09, nhưng còn hai ví dụ cuối cùng thì sao? Các mục danh sách riêng lẻ có các loại khác nhau và trong trường hợp đó, biến loại
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
35 làm hết sức mình để phù hợp:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
6

Như bạn đã thấy

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

26 là một kiểu con của
String thing;
thing = "Hello";
09, một lần nữa là một loại phụ của
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88. Vì vậy, trong ví dụ thứ ba, giá trị trả về của
String thing;
thing = "Hello";
44 được đảm bảo là thứ có thể được coi là
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88. Trong ví dụ cuối cùng, không có mối quan hệ phân nhóm giữa
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15 và
String thing;
thing = "Hello";
09, vì vậy điều tốt nhất có thể nói về giá trị trả về là nó là một đối tượng.

Lưu ý rằng không có ví dụ nào trong số này nêu ra một lỗi loại. Có cách nào để nói với trình kiểm tra loại rằng

String thing;
thing = "Hello";
44 nên chấp nhận cả chuỗi và số, nhưng không phải cả hai cùng một lúc?

Bạn có thể ràng buộc các biến loại bằng cách liệt kê các loại chấp nhận được:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
7

Bây giờ

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
35 chỉ có thể là
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15 hoặc
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88 và MyPy sẽ lưu ý rằng ví dụ cuối cùng là một lỗi:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
8

Cũng lưu ý rằng trong ví dụ thứ hai, loại được coi là

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88 mặc dù danh sách đầu vào chỉ chứa các đối tượng
String thing;
thing = "Hello";
09. Điều này là do
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
35 bị giới hạn ở các chuỗi và phao và
String thing;
thing = "Hello";
09 là một loại phụ của
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

88.

Trong trò chơi bài của chúng tôi, chúng tôi muốn hạn chế

String thing;
thing = "Hello";
44 được sử dụng cho
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15 và
String thing;
thing = "Hello";
33:

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
9

Chúng tôi đã đề cập ngắn gọn rằng

String thing;
thing = "Hello";
27 đại diện cho cả danh sách và bộ dữ liệu. Như chúng tôi đã lưu ý, một
String thing;
thing = "Hello";
27 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ó
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

08 và
String thing;
thing = "Hello";
30 được triển khai.

Các loại vịt và giao thức

Nhớ lại ví dụ sau từ phần giới thiệu:

def len(obj):
    return obj.__len__()

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

07 có thể trả về độ dài của bất kỳ đối tượng nào đã thực hiện phương thức
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

08. Làm thế nào chúng ta có thể thêm gợi ý loại vào
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

07, và đặc biệt là đối số
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

13?

Câu trả lời ẩn đằng sau thuật ngữ phân nhóm cấu trúc âm thanh học thuật. Một cách để phân loại các hệ thống loại là bằng cách chúng là danh nghĩa hay cấu trúc:nominal or structural:

  • Trong một hệ thống danh nghĩa, so sánh giữa các loại dựa trên tên và khai báo. Hệ thống loại Python chủ yếu là danh nghĩa, trong đó

    String thing;
    thing = "Hello";
    
    09 có thể được sử dụng thay cho
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    88 vì mối quan hệ phân nhóm của chúng.nominal system, comparisons between types are based on names and declarations. The Python type system is mostly nominal, where an
    String thing;
    thing = "Hello";
    
    09 can be used in place of a
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    88 because of their subtype relationship.

  • Trong một hệ thống kết cấu, so sánh giữa các loại dựa trên cấu trúc. Bạn có thể xác định loại cấu trúc

    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    65 bao gồm tất cả các trường hợp xác định
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    08, không phân biệt loại danh nghĩa của chúng.structural system, comparisons between types are based on structure. You could define a structural type
    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    65 that includes all instances that define
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    08, irrespective of their nominal type.

Có một công việc đang diễn ra để đưa một hệ thống loại cấu trúc chính thức đến Python thông qua PEP 544 nhằm mục đích thêm một khái niệm gọi là các giao thức. Hầu hết PEP 544 đã được triển khai trong MyPy mặc dù.

Một giao thức chỉ định một hoặc nhiều phương thức phải được thực hiện. Ví dụ: tất cả các lớp xác định

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

08 thực hiện giao thức
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
68. Do đó, chúng tôi có thể chú thích
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

07 như sau:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
1

Các ví dụ khác về các giao thức được xác định trong mô -đun

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

46 bao gồm
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
71,
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
72,
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
73 và
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
74.

Bạn cũng có thể xác định các giao thức của riêng bạn. Điều này được thực hiện bằng cách kế thừa từ

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
75 và xác định chữ ký chức năng (với các cơ quan chức năng trống) mà giao thức mong đợi. Ví dụ sau đây cho thấy cách
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

07 và
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
65 có thể được thực hiện:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
2

Tại thời điểm viết hỗ trợ cho các giao thức tự xác định vẫn là thử nghiệm và chỉ có sẵn thông qua mô-đun

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
78. Mô -đun này phải được cài đặt rõ ràng từ PYPI bằng cách thực hiện
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
79.

Loại >>> class TheHobbit: ... def __len__(self): ... return 95022 ... >>> the_hobbit = TheHobbit() >>> len(the_hobbit) 95022 80

Một mẫu phổ biến trong Python là sử dụng

String thing;
thing = "Hello";
39 làm giá trị mặc định cho một đối số. Điều này thường được thực hiện để tránh các vấn đề với các giá trị mặc định có thể thay đổi hoặc để có một hành vi đặc biệt của Sentinel Value.

Trong ví dụ thẻ, hàm

String thing;
thing = "Hello";
45 sử dụng
String thing;
thing = "Hello";
39 làm giá trị sentinel cho
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
84 nói rằng nếu không có trình phát bắt đầu nào được đưa ra, nên chọn ngẫu nhiên:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
3

Thách thức này tạo ra cho các gợi ý loại là nói chung

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
84 nên là một chuỗi. Tuy nhiên, nó cũng có thể lấy giá trị phi chuỗi đặc biệt
String thing;
thing = "Hello";
39.

Để chú thích các đối số như vậy, bạn có thể sử dụng loại

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
80:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
4

Loại

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
80 chỉ đơn giản nói rằng một biến có loại được chỉ định hoặc là
String thing;
thing = "Hello";
39. Một cách tương đương để chỉ định tương tự sẽ bằng cách sử dụng loại
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
90:
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
91

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

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
80 hoặc
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
90, bạn phải quan tâm rằng biến có loại chính xác khi bạn hoạt động trên đó. Điều này được thực hiện trong ví dụ bằng cách kiểm tra xem
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
94. Không làm như vậy sẽ gây ra cả lỗi loại tĩnh cũng như lỗi thời gian chạy có thể:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
5

Mypy nói với bạn rằng bạn chưa quan tâm đến trường hợp

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
84 là
String thing;
thing = "Hello";
39:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
6

Ví dụ: đối tượng (ive) 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 tôi thảo luận về cách chú thích đúng các lớp và phương pháp.

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

String thing;
thing = "Hello";
33,
String thing;
thing = "Hello";
34,
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
99 và
def len(obj):
    return obj.__len__()
00 trông giống như sau:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
7

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

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

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

def len(obj):
    return obj.__len__()
01 không cần phải được chú thích, vì nó luôn luôn là một thể hiện lớp. Các loại của lớp
String thing;
thing = "Hello";
33 rất dễ thêm:

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
8

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

def len(obj):
    return obj.__len__()
03 luôn phải có
String thing;
thing = "Hello";
39 dưới dạng loại trả về của nó.

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

Có một sự tương ứng giữa các lớp và loại. Ví dụ: tất cả các trường hợp của lớp

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

Ví dụ, về cơ bản là

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

>>> print(headline("python type checking"))
Python Type Checking
--------------------

>>> print(headline("python type checking", align=False))
oooooooooooooo Python Type Checking oooooooooooooo
9

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

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

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

def len(obj):
    return obj.__len__()
11 trả về một đối tượng có loại
String thing;
thing = "Hello";
34. Tuy nhiên, bạn có thể chỉ cần thêm
def len(obj):
    return obj.__len__()
13 vì lớp
String thing;
thing = "Hello";
34 chưa được xác định đầy đủ.

Thay vào đó, bạn được phép sử dụng chuỗi chữ trong các 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 tài liệu tham khảo bản thân và chuyển tiếp. Phương pháp

def len(obj):
    return obj.__len__()
15 nên sử dụng các chữ cái như vậy cho các loại của nó:

def headline(text: str, align: bool = True) -> str:
    ...
0

Lưu ý rằng lớp

>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
99 cũng sẽ tham chiếu lớp
String thing;
thing = "Hello";
34. Tuy nhiên, điều này không có vấn đề gì, vì
String thing;
thing = "Hello";
34 được xác định trước
>>> class TheHobbit:
...     def __len__(self):
...         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
99:

def headline(text: str, align: bool = True) -> str:
    ...
1

Thông thường các chú thích không được sử dụng trong thời gian chạy. Điều này đã đưa ra cánh cho ý tưởng hoãn đánh giá các chú thích. Thay vì đánh giá các chú thích là 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.0 huyền thoại. Tuy nhiên, trong Python 3.7 trở lên, các tài liệu tham khảo chuyển tiếp có sẵn thông qua nhập

def len(obj):
    return obj.__len__()
20:

def headline(text: str, align: bool = True) -> str:
    ...
2

Với nhập

def len(obj):
    return obj.__len__()
20, bạn có thể sử dụng
String thing;
thing = "Hello";
34 thay vì
def len(obj):
    return obj.__len__()
23 ngay cả trước khi
String thing;
thing = "Hello";
34 được xác định.

Trở về def len(obj): return obj.__len__() 01 hoặc def len(obj): return obj.__len__() 26

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

def len(obj):
    return obj.__len__()
01 hoặc
def len(obj):
    return obj.__len__()
26. Một phần, điều này là không cần thiết vì
def len(obj):
    return obj.__len__()
01 chỉ vào một thể hiện của lớp, vì vậy nó sẽ có loại của lớp. Trong ví dụ
String thing;
thing = "Hello";
33,
def len(obj):
    return obj.__len__()
01 có loại ngầm
String thing;
thing = "Hello";
33. Ngoài ra, việc thêm loại này rõ ràng sẽ cồng kềnh vì lớp chưa được xác định. Bạn sẽ phải sử dụng cú pháp theo nghĩa đen của chuỗi,
def len(obj):
    return obj.__len__()
33.

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

def len(obj):
    return obj.__len__()
01 hoặc
def len(obj):
    return obj.__len__()
26. Hãy xem xét những gì xảy ra nếu bạn có một siêu lớp mà các lớp khác kế thừa và có các phương thức trả về
def len(obj):
    return obj.__len__()
01 hoặc
def len(obj):
    return obj.__len__()
26:

def headline(text: str, align: bool = True) -> str:
    ...
3

Trong khi mã chạy mà không có vấn đề, MyPy sẽ gắn cờ một vấn đề:

def headline(text: str, align: bool = True) -> str:
    ...
4

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

def len(obj):
    return obj.__len__()
38 và
def len(obj):
    return obj.__len__()
39 được thừa hưởng sẽ trả về một
def len(obj):
    return obj.__len__()
40, chú thích nói rằng họ trả lại một
def len(obj):
    return obj.__len__()
41.

Trong những trường hợp như thế này, bạn muốn cẩn thận hơn để đảm bảo chú thích là chính xác. Loại trả về phải khớp với loại

def len(obj):
    return obj.__len__()
01 hoặc loại thể hiện của
def len(obj):
    return obj.__len__()
26. Điều này có thể được thực hiện bằng cách sử dụng các biến loại theo dõi những gì thực sự được chuyển đến
def len(obj):
    return obj.__len__()
01 và
def len(obj):
    return obj.__len__()
26:

def headline(text: str, align: bool = True) -> str:
    ...
5

Có một vài điều cần lưu ý trong ví dụ này:

  • Biến loại

    def len(obj):
        return obj.__len__()
    
    46 được sử dụng để biểu thị rằng các giá trị trả về có thể là các trường hợp của các lớp con của
    def len(obj):
        return obj.__len__()
    
    41.

  • Chúng tôi chỉ định rằng

    def len(obj):
        return obj.__len__()
    
    41 là giới hạn trên cho
    def len(obj):
        return obj.__len__()
    
    46. Chỉ định
    def len(obj):
        return obj.__len__()
    
    50 có nghĩa là
    def len(obj):
        return obj.__len__()
    
    46 sẽ chỉ là
    def len(obj):
        return obj.__len__()
    
    41 hoặc một trong các lớp con của nó. Điều này là cần thiết để hạn chế đúng các loại được phép.

  • Cấu trúc

    def len(obj):
        return obj.__len__()
    
    53 là gõ tương đương
    >>> thing = "Hello"
    >>> type(thing)
    
    
    >>> thing = 28.1
    >>> type(thing)
    
    
    00. Bạn cần lưu ý rằng phương thức lớp mong đợi một lớp và trả về một thể hiện của lớp đó.

Chú thích def len(obj): return obj.__len__() 55 và def len(obj): return obj.__len__() 56

Trong phiên bản định hướng đối tượng của trò chơi, chúng tôi đã thêm tùy chọn để đặt tên cho người chơi trên dòng lệnh. Điều này được thực hiện bằng cách liệt kê tên người chơi theo tên của chương trình:

def headline(text: str, align: bool = True) -> str:
    ...
6

Điều này được thực hiện bằng cách giải nén và chuyển trong

def len(obj):
    return obj.__len__()
57 đến
def len(obj):
    return obj.__len__()
58 khi nó khởi tạo. Phương pháp
def len(obj):
    return obj.__len__()
03 sử dụng
def len(obj):
    return obj.__len__()
60 để đóng gói các tên đã cho thành một tuple.

Về các chú thích loại: Mặc dù

String thing;
thing = "Hello";
12 sẽ là một bộ chuỗi, bạn chỉ nên chú thích loại của mỗi tên. Nói cách khác, bạn nên sử dụng
>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

15 chứ không phải
def len(obj):
    return obj.__len__()
63:

def headline(text: str, align: bool = True) -> str:
    ...
7

Tương tự, nếu bạn có chức năng hoặc phương thức chấp nhận

def len(obj):
    return obj.__len__()
56, thì bạn chỉ nên chú thích loại của từng đối số từ khóa có thể.

Đồ gọi

Các chức năng là các đối tượng hạng nhất trong Python. Điều này có nghĩa là bạn có thể sử dụng các chức năng làm đối số cho các chức năng khác. Điều đó cũng có nghĩa là bạn cần có khả năng thêm các gợi ý loại đại diện cho các chức năng.

Các chức năng, cũng như lambdas, phương pháp và lớp, được đại diện bởi

def len(obj):
    return obj.__len__()
65. Các loại của các đối số và giá trị trả về thường cũng được thể hiện. Chẳng hạn,
def len(obj):
    return obj.__len__()
66 đại diện cho một hàm với ba đối số với các loại
def len(obj):
    return obj.__len__()
67,
def len(obj):
    return obj.__len__()
68 và
def len(obj):
    return obj.__len__()
69, tương ứng. Loại trả về của hàm là
def len(obj):
    return obj.__len__()
70.

Trong ví dụ sau, hàm

def len(obj):
    return obj.__len__()
71 gọi một hàm đã cho hai lần và in các giá trị trả về:

def headline(text: str, align: bool = True) -> str:
    ...
8

Lưu ý chú thích của đối số

def len(obj):
    return obj.__len__()
72 thành
def len(obj):
    return obj.__len__()
71 trên dòng 5. Nó nói rằng
def len(obj):
    return obj.__len__()
72 phải là một cuộc gọi có thể gọi với một đối số chuỗi, cũng trả về một chuỗi. Một ví dụ về một cuộc gọi như vậy là
def len(obj):
    return obj.__len__()
75 được xác định trên dòng 9.

Hầu hết các loại có thể gọi có thể được chú thích theo cách tương tự. Tuy nhiên, nếu bạn cần linh hoạt hơn, hãy xem các giao thức gọi lại và các loại có thể gọi được mở rộng.

Ví dụ: Trái tim

Hãy để kết thúc với một ví dụ đầy đủ về trò chơi của trái tim. Bạn có thể đã biết trò chơi này từ các mô phỏng máy tính khác. Đây là bản tóm tắt nhanh chóng về các quy tắc:

  • Bốn người chơi chơi với một bàn tay gồm 13 thẻ.

  • Người chơi giữ ♣ 2 bắt đầu vòng đầu tiên và phải chơi ♣ 2.

  • Người chơi thay phiên nhau chơi bài, theo sau bộ đồ hàng đầu nếu có thể.

  • Người chơi chơi thẻ cao nhất trong bộ đồ hàng đầu sẽ thắng trò lừa và trở thành người chơi bắt đầu trong lượt tiếp theo.

  • Một người chơi không thể dẫn đầu với một ♡ cho đến khi một ♡ đã được chơi trong một thủ thuật sớm hơn.

  • Sau khi tất cả các thẻ được phát, người chơi sẽ nhận được điểm nếu họ lấy một số thẻ nhất định:

    • 13 điểm cho ♠ Q
    • 1 điểm cho mỗi ♡
  • Một trò chơi kéo dài vài vòng, cho đến khi một người chơi có 100 điểm trở lên. Người chơi có điểm ít nhất chiến thắng.

Thông tin chi tiết có thể được tìm thấy trực tuyến.

Không có nhiều khái niệm đánh máy mới trong ví dụ này mà bạn chưa thấy. Do đó, chúng tôi không đi qua mã này một cách chi tiết, nhưng để lại nó như một ví dụ về mã được chú thích.

Bạn có thể tải xuống mã này và các ví dụ khác từ GitHub:

def headline(text: str, align: bool = True) -> str:
    ...
9

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 các biến

    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    90 hoặc loại, bạn có thể sử dụng trình trang trí
    def len(obj):
        return obj.__len__()
    
    77. Xem
    def len(obj):
        return obj.__len__()
    
    78 để 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

    def len(obj):
        return obj.__len__()
    
    79 bất cứ nơi nào dự kiến ​​
    >>> class TheHobbit:
    ...     def __len__(self):
    ...         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    99.

  • Khi một lớp con tái tạo một phương thức từ một siêu lớp, các chú thích loại phải khớp. Xem ví dụ

    def len(obj):
        return obj.__len__()
    
    81.

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ẻ nào để chơi. Sau đây là một ví dụ về chơi trò chơi, với các dòng được tô sáng hiển thị nơi người chơi đưa ra lựa chọn:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
0

Kiểm tra loại tĩnh

Cho đến nay bạn đã thấy cách thêm gợi ý loại vào mã của bạn. Trong phần này, bạn sẽ tìm hiểu thêm về cách thực sự thực hiện kiểm tra mã tĩnh của mã Python.

Dự án MyPy

Mypy đã được bắt đầu bởi Jukka Lehtosalo trong quá trình tiến sĩ của mình. Các nghiên cứu tại Cambridge vào khoảng năm 2012. MyPy ban đầu được hình dung là một biến thể Python với sự động lực và gõ tĩnh liền mạch. Xem các slide 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ò lớn trong dự án MyPy. Trên thực tế, khẩu hiệu Dynamic Dynamic và Gõ tĩnh mạch chủ động vẫn có thể nhìn thấy nổi bật trên trang chủ của Mypy và mô tả động lực sử dụng gợi ý loại 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 của 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 loại của nó. Theo đề xuất của Guido Van Rossum, Mypy đã được viết lại để sử dụng các chú thích thay thế. Ngày nay, MyPy là một trình kiểm tra loại 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 dễ dàng được thực hiện nhất bằng cách sử dụng

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

36:

Với MyPy được cài đặt, bạn có thể chạy nó dưới dạng chương trình dòng lệnh thông thường:

Chạy MyPy trên tệp Python

def len(obj):
    return obj.__len__()
83 của bạn sẽ kiểm tra nó để biết các 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 nhập kiểm tra mã của bạn. Vì MyPy vẫn còn được phát triển rất tích cực, các tùy chọn dòng lệnh có khả năng thay đổi giữa các phiên bản. Bạn nên tham khảo Trợ giúp MyPy, để xem cài đặt nào là mặc định trên phiên bản của bạn:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
1

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 cùng xem xét một số lựa 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 mà không có gợi ý loại, bạn có thể muốn im lặng các cảnh báo của Mypy về những điều này. Điều này có thể được thực hiện với tùy chọn

def len(obj):
    return obj.__len__()
84.

Ví dụ sau sử dụng Numpy để tính và in cosin của một số số:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
2

Lưu ý rằng

def len(obj):
    return obj.__len__()
85 chỉ có sẵn trong phiên bản 1.15 và sau đó là Numpy. Chạy ví dụ này in một số số vào bảng điều khiển:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
3

Đầu ra thực tế của ví dụ này là không quan trọng. Tuy nhiên, bạn nên lưu ý rằng đối số

def len(obj):
    return obj.__len__()
86 được chú thích bằng
def len(obj):
    return obj.__len__()
87 trên dòng 5, vì chúng tôi muốn in cosin của một loạt các số đầy đủ.

Bạn có thể chạy MyPy trên tệp này như bình thường:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
4

Những cảnh báo này có thể không ngay lập tức có ý nghĩa với bạn, nhưng bạn sẽ tìm hiểu về các cuống và được đánh máy sớm. 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 gợi ý 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 bị làm phiền để bạn có thể im lặng những tin nhắn này:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
5

Nếu bạn sử dụng tùy chọn dòng lệnh

def len(obj):
    return obj.__len__()
88, MyPy sẽ không cố gắng theo dõi hoặc cảnh báo về bất kỳ nhập khẩu nào bị thiếu. Điều này có thể hơi nặng tay, vì nó cũng bỏ qua những sai lầm thực sự, như viết sai tên của một gói.

Hai cách xử lý các gói của bên thứ ba ít xâm nhập hơn là sử dụng các nhận xét loại hoặc tệp cấu hình.

Trong một ví dụ đơn giản như ở trên, bạn có thể im lặng cảnh báo

def len(obj):
    return obj.__len__()
89 bằng cách thêm một loại nhận xét vào dòng chứa nhập khẩu:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
6

Theo nghĩa đen

def len(obj):
    return obj.__len__()
90 bảo Mypy bỏ qua việc nhập khẩu Numpy.

Nếu bạn có một số tệp, có thể dễ dàng theo dõi việc nhập nào bỏ qua trong tệp cấu hình. MyPy đọc một tệp có tên

def len(obj):
    return obj.__len__()
91 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 gọi là
def len(obj):
    return obj.__len__()
92 và có thể chứa các phần cụ thể của mô -đun có dạng
def len(obj):
    return obj.__len__()
93.

Tệp cấu hình sau đây sẽ bỏ qua rằng Numpy bị thiếu gợi ý loại:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
7

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 toàn cầu. Xem tài liệu để cho biết thêm thông tin chi tiết.

Thêm cuống

Loại gợi ý có sẵn cho tất cả các gói trong thư viện tiêu 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. Để theo dõi trước tiên bạn nên cài đặt Parse:

Phân tích có thể được sử dụng để nhận ra các mẫu đơn giản. Dưới đâ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:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
8

Dòng chính được xác định trong ba dòng cuối cùng: yêu cầu tên của bạn, phân tích câu trả lời và in một lời chào. Gói

def len(obj):
    return obj.__len__()
94 được gọi trên dòng 14 để cố gắng tìm một tên dựa trên một trong các mẫu được liệt kê trên các dòng 7-11.

Chương trình có thể được sử dụng như sau:

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
9

Lưu ý rằng mặc dù tôi trả lời

def len(obj):
    return obj.__len__()
95, chương trình cho rằng
def len(obj):
    return obj.__len__()
96 không phải là một phần của tên 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 nó không. Thay đổi dòng 16 từ

def len(obj):
    return obj.__len__()
97 thành
def len(obj):
    return obj.__len__()
98. Điều này sẽ trả về một đối tượng
def len(obj):
    return obj.__len__()
99 thay vì chuỗi chứa tên.

Tiếp theo chạy mypy trên chương trình:

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
0

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

def len(obj):
    return obj.__len__()
94. Bạn có thể cố gắng bỏ qua việc nhập:

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
1

Thật không may, bỏ qua việc nhập có nghĩa là MyPy không có cách nào để khám phá lỗi trong chương trình của chúng tôi. Một giải pháp tốt hơn sẽ là thêm 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 một 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 phải là triển khai của chúng. Chức năng chính của họ là thêm gợi ý loại vào mã mà bạn vì một số lý do có thể thay đổi. Để cho thấy 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 một thư mục chung và đặt biến môi trường

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
01 để trỏ đến thư mục này. Trên Mac và Linux, bạn có thể đặt
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
01 như sau:

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
2

Bạn có thể đặt biến vĩnh viễn bằng cách thêm dòng vào tệp

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
03 của bạn. 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
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
01.

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à

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
05. 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ố
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
06. Để lại tệp này để trống ngay bây giờ. Sau đó chạy lại mypy:

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
3

Nếu bạn đã thiết lập mọi thứ một cách 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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
05 mới để tìm ra hàm nào có sẵn trong gói
def len(obj):
    return obj.__len__()
94. Vì tệp sơ khai trống, MyPy cho rằng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
09 không tồn tại và sau đó đưa ra lỗi bạn thấy ở trên.

Ví dụ sau đây không thêm các loại cho toàn bộ gói

def len(obj):
    return obj.__len__()
94. Thay vào đó, nó hiển thị các gợi ý loại bạn cần thêm để MyPy gõ Kiểm tra việc bạn sử dụng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
09:

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
4

Ellipsis

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
12 là một phần của tệp và nên được viết chính xác như trên. Tệp sơ khai chỉ nên chứa các gợi ý loại cho các biến, thuộc tính, hàm và phương thức, do đó các triển khai phải được bỏ ra và thay thế bằng các dấu hiệu
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
12.

Cuối cùng, MyPy có thể phát hiện ra lỗi mà chúng tôi đã giới thiệu:

 1# headlines.py
 2
 3def headline(text: str, align: bool = True) -> str:
 4    if align:
 5        return f"{text.title()}\n{'-' * len(text)}"
 6    else:
 7        return f" {text.title()} ".center(50, "o")
 8
 9print(headline("python type checking"))
10print(headline("use mypy", align="center"))
5

Điều này chỉ thẳng vào dòng 16 và thực tế là chúng ta trả về một đối tượng

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
14 chứ không phải chuỗi tên. Thay đổi
def len(obj):
    return obj.__len__()
98 trở lại
def len(obj):
    return obj.__len__()
97 và chạy lại MyPy để thấy rằng nó rất vui.

Đánh máy

Bạn đã thấy cách sử dụng cuống để thêm gợi ý loại mà không thay đổi 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ờ, nó sẽ rất hiệu quả 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 họ đang sử dụng.

Typeshed là một kho lưu trữ GitHub chứa các gợi ý loại cho thư viện tiêu chuẩn Python, cũng như nhiều gói của bên thứ ba. Typeshed đi kèm với mypy vì vậy nếu bạn đang sử dụng một gói đã có các gợi ý loại được xác định trong đánh máy, kiểm tra loại sẽ chỉ hoạt động.

Bạn cũng có thể đóng góp gợi ý loại cho đánh máy. Đảm bảo trước tiên để có sự cho phép của 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 mã nguồn chính là cách tiếp cận ưa thích.

Máy 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 việc kiểm tra loại bằng MyPy. Tuy nhiên, có những người kiểm tra loại tĩnh khác trong hệ sinh thái Python.

Biên tập viên Pycharm đi kèm với trình kiểm tra kiểu riêng của nó. Nếu bạn đang sử dụng Pycharm để viết mã Python của mình, nó sẽ được tự động nhập.PyCharm editor comes with its own type checker included. If you are using PyCharm to write your Python code, it will be automatically type checked.

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 suất. Mặc dù có một số khác biệt, các chức năng PYRE chủ yếu tương tự như MyPy. Xem tài liệu nếu bạn quan tâm đến việc thử Pyre.Pyre. One of its stated goals is to be fast and performant. While there are some differences, Pyre functions mostly similar to Mypy. See the documentation if you’re interested in trying out Pyre.

Hơn nữa, Google đã tạo ra pytype. Trình kiểm tra loại này cũng hoạt động chủ yếu 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 bảo vệ và thậm chí thêm các chú thích vào mã tự động. Xem tài liệu QuickStart để biết thêm thông tin.Pytype. This type checker also works mostly the same as Mypy. In addition to checking annotated code, Pytype has some support for running type checks on unannotated code and even adding annotations to code automatically. See the quickstart document for more information.

Sử dụng các loại trong thời gian chạy

Như một lưu ý cuối cùng, nó có thể sử dụng các gợi ý loại trong thời gian chạy trong khi thực hiện chương trình Python của bạn. Kiểm tra loại thời gian chạy có thể sẽ không bao giờ được hỗ trợ tự nhiên trong Python.

Tuy nhiên, các gợi ý loại có sẵn trong thời gian chạy trong từ điển

>>> thing = "Hello"
>>> type(thing)


>>> thing = 28.1
>>> type(thing)

89 và bạn có thể sử dụng chúng để kiểm tra loại nếu bạn 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 thực thi, pydantic hoặc pytypes cho một số ví dụ.Enforce, Pydantic, or Pytypes for some examples.

Một cách sử dụng khác của các 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 gõ tĩnh. Tuy nhiên, vì phiên bản 0.27 Cython cũng đã hỗ trợ các chú thích loại. Gần đây, dự án MYPYC đã trở nên có sẵn. Mặc dù chưa sẵn sàng để sử dụng chung, nó có thể biên dịch một số mã Python có tính toán cho các phần mở rộng C.Cython project uses a hybrid C/Python language to write statically typed Python code. However, since version 0.27 Cython has also supported type annotations. Recently, the Mypyc project has become available. While not yet ready for general use, it can compile some type annotated Python code to C extensions.

Sự kết luận

Loại 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. Loại gợi ý don lồng làm cho bạn có khả năng viết bất kỳ mã nào mà bạn có thể viết mà không cần sử dụng gợi ý loại. Thay vào đó, sử dụng gợi ý loại giúp bạn dễ dàng lý luận về mã, tìm các lỗi tinh tế và duy trì kiến ​​trúc sạch.

Trong hướng dẫn này, bạn đã học được cách các gợi ý loại hoạt động trong Python và cách gõ dần dần làm cho kiểm tra loại 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 ý loại và cách chúng có thể được thêm vào mã bằng cách sử dụng các chú thích hoặc nhận xét loại. Cuối cùng, bạn đã thấy nhiều loại khác nhau mà Python hỗ trợ, cũng như cách thực hiện kiểm tra loại tĩnh.

Có nhiều tài nguyên để tìm hiểu thêm về kiểm tra loại tĩnh trong Python. PEP 483 và PEP 484 cung cấp nhiều nền tảng về cách kiểm tra loại được thực hiện trong Python. Tài liệu MyPy có một phần tham chiếu tuyệt vời chi tiết tất cả các loại khác nhau có sẵn.

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn về sự hiểu biết của bạn: Kiểm tra loại Python This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Python Type Checking

Trình kiểm tra loại Python là gì?

Kiểm tra loại hoặc gợi ý là một tính năng mới hơn của Python đã được thêm vào Python 3.5. Loại gợi ý còn được gọi là chú thích loại. Loại gợi ý đang thêm cú pháp đặc biệt vào các chức năng và khai báo biến cho nhà phát triển biết loại đối số hoặc biến là gì.adding special syntax to functions and variable declarations that tell the developer what type the argument or variable is.

Trình kiểm tra loại là gì?

Kiểm tra loại là quá trình xác minh và thực thi các ràng buộc của các loại trong các giá trị.Trình biên dịch phải kiểm tra xem chương trình nguồn nên tuân theo các quy ước của cú pháp và ngữ nghĩa của ngôn ngữ nguồn và nó cũng nên kiểm tra các quy tắc loại của ngôn ngữ.the process of verifying and enforcing constraints of types in values. A compiler must check that the source program should follow the syntactic and semantic conventions of the source language and it should also check the type rules of the language.

Là loại kiểm tra chuỗi trong python?

Để kiểm tra xem một biến có chứa giá trị là một chuỗi không, hãy sử dụng hàm tích hợp isinstance.Hàm isinstance có hai đối số.Đầu tiên là biến của bạn.Thứ hai là loại bạn muốn kiểm tra.use the isinstance built-in function. The isinstance function takes two arguments. The first is your variable. The second is the type you want to check for.

Bạn có nên kiểm tra các loại trong Python?

Đóng Suy nghĩ - KIỂM TRA PYTHON Loại phương thức loại () là phương thức được khuyến nghị nhất để kiểm tra loại đối tượng.Phương pháp isinstance nổi bật vì nó có thể được sử dụng để kiểm tra xem một đối tượng cũng là một phần của lớp.Do đó, tôi luôn khuyên bạn nên sử dụng phương thức loại () để kiểm tra loại đối tượng.The type() method is the most recommended method to check the type of an object. The isinstance method stands out as it can be used to check if an object is part of a class as well. Hence, I would always recommend using the type() method to check the type of an object.