Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

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

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

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

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

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

Loại hệ thống

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
09 là một ví dụ về đối tượng thuộc loại số

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

Nhập động

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

>>>

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

>>> thing = 28.1
>>> type(thing)
<class 'float'>
10, nó sẽ tăng
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
12 vì bạn không thể cộng một số nguyên và một chuỗi trong Python

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

>>>

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
13 trả về loại đối tượng. Những ví dụ này xác nhận rằng loại
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
14 được phép thay đổi và Python suy luận chính xác loại khi nó thay đổi

Nhập tĩnh

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

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

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

________số 8_______

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
14 được liên kết với loại
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

>>> thing = 28.1
>>> type(thing)
<class 'float'>
14 đượ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à một đối tượng
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
16. Chẳng hạn, nếu sau này bạn nói
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
19 thì trình biên dịch sẽ báo lỗi do các kiểu không tương thích

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

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

gõ vịt

Một thuật ngữ khác thường được sử dụng khi nói về Python là duck typing. Biệt danh này bắt nguồn từ câu “nếu nó đi như vịt và kêu quạc quạc như vịt, thì nó phải là vịt” (hoặc )

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 trên bất kỳ đối tượng Python nào xác định phương thức
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
21

>>>

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 về cơ bản tương đương như sau

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

Để gọi

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
25, ràng buộc thực sự duy nhất đối với
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
26 là nó phải xác định một phương thức
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
21. Mặt khác, đối tượng có thể thuộc các loại khác nhau như
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28,
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
29,
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
30 hoặc
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
31

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

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

xin chào các loại

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

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ề dòng tiêu đề được căn trái với phần gạch chân. Bằng cách đặt cờ

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
32 thành
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
33, bạn có thể đặt dòng tiêu đề ở giữa với đường xung quanh là
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
34

>>>

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

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

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

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

Cú pháp

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
35 nói rằng đối số
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
36 phải thuộc loại
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28. Tương tự, đối số tùy chọn
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
32 phải có loại
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 với giá trị mặc định là
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
40. Cuối cùng, ký hiệu
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
41 xác định rằng
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
42 sẽ trả về một chuỗi

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
32, thì mã vẫn chạy mà không có bất kỳ sự cố hoặc cảnh báo nào

>>>_______ 48 _______

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
49. Sử dụng
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
50 sẽ không có tác dụng mong muốn vì
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
51 cũng đúng

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

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

Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
52

$ pip install mypy

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
53

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
0

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
42 và hai ví dụ đang sử dụng nó

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
1

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
32 mà bạn đang chuyển vào. Bạn cũng có thể đổi tên cờ
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
32 thành tên nào đó ít khó hiểu hơn

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
2

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
32 thành
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
58 và sử dụng đúng giá trị Boolean cho
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
58 khi gọi
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
42. Mã bây giờ vượt qua Mypy

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
3

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
4

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

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

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

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

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

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

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

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

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

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

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

  • Gõ gợi ý giới thiệu một hình phạt nhẹ trong thời gian khởi động. Nếu bạn cần sử dụng thì thời gian nhập có thể là đáng kể, đặc biệt là trong các tập lệnh ngắn

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

Bạn sẽ tìm hiểu về mô-đun

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
64 phải là một tệp trống, trong khi
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
65 phải chứa dòng sau

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
5

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62 mất bao nhiêu thời gian bằng cách sử dụng tiện ích
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
67

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
6

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
7

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62 mất khoảng 17 mili giây trên Python 3. 6

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
8

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62 giảm từ 17 xuống còn khoảng 6 mili giây—nhanh hơn gần 3 lần

Sử dụng

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
72

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
72 trong thư viện chuẩn. Thông thường, chúng tôi sẽ trực tiếp sử dụng
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
72 cho thời gian ở trên. Tuy nhiên,
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
9

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
67 đo được. Điều mà
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
72 đã thực sự làm là chạy câu lệnh
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
78 30 triệu lần, trong khi Python thực sự chỉ nhập
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62 một lần

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
72 chỉ chạy một lần

String thing;
thing = "Hello";
0

Những kết quả này có cùng thang điểm với kết quả từ

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
67 ở trên. Tuy nhiên, vì chúng chỉ dựa trên một lần thực thi mã nên chúng không đáng tin cậy bằng những mã dựa trên nhiều lần chạy

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

Tùy chọn

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
83 mới

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
84, bạn sẽ nhận được báo cáo về tất cả các lần nhập được thực hiện

String thing;
thing = "Hello";
1

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

>>> thing = 28.1
>>> type(thing)
<class 'float'>
86 và
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
87 mà
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62 phụ thuộc vào

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

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

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

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

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

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

    >>> thing = "Hello"
    >>> type(thing)
    <class 'str'>
    
    >>> thing = 28.1
    >>> type(thing)
    <class 'float'>
    
    89,
    >>> thing = "Hello"
    >>> type(thing)
    <class 'str'>
    
    >>> thing = 28.1
    >>> type(thing)
    <class 'float'>
    
    90, Trình đọc Python thực của riêng chúng tôi và chính Mypy

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

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

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

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

Chú thích

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

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

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

Chú thích chức năng

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

String thing;
thing = "Hello";
2

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
91, trong khi kiểu trả về được chú thích bằng cách sử dụng
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
92. Lưu ý rằng chú thích phải là biểu thức Python hợp lệ

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

String thing;
thing = "Hello";
3

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
93 đặc biệt trên hàm

>>>

String thing;
thing = "Hello";
4

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
94 và
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

>>> thing = 28.1
>>> type(thing)
<class 'float'>
96

String thing;
thing = "Hello";
5

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

String thing;
thing = "Hello";
6

Ngay cả khi không có bất kỳ chú thích nào, Mypy đã suy luận chính xác các loại của biến ____ _ _ _ _ _ _ _ _ _ _ _ được tích hợp sẵn, cũng như các biến cục bộ của chúng ta _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
96 dưới dạng tập lệnh Python, nó sẽ gặp sự cố với
String thing;
thing = "Hello";
01 vì
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
94 không phải là hàm mà trình thông dịch Python biết đến

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

String thing;
thing = "Hello";
03' không được xác định", bạn có thể cần cập nhật cài đặt Mypy của mình. The
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
95 expression is available in Mypy version 0. 610 trở lên

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

Chú thích biến

Trong định nghĩa của

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

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

String thing;
thing = "Hello";
7

Biến

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

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

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

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

String thing;
thing = "Hello";
10

>>>

String thing;
thing = "Hello";
8

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

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

>>>

String thing;
thing = "Hello";
9

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

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

Loại Nhận xét

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

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

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

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

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

String thing;
thing = "Hello";
10

>>>

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

Chú thích loại phải bắt đầu bằng _______ 15 chữ và ở cùng dòng hoặc dòng sau với định nghĩa hàm. Nếu bạn muốn chú thích một hàm có nhiều đối số, bạn viết từng loại cách nhau bằng dấu phẩy

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

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

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

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

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

Nếu bạn có sai sót, chẳng hạn nếu bạn tình cờ gọi cho

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
42 với
String thing;
thing = "Hello";
17 trên dòng 10, Mypy sẽ cho bạn biết

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

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

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

Trong ví dụ này,

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

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

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

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

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

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

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

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28,
String thing;
thing = "Hello";
07 và
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

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

  • The type of like tuples, lists and dictionaries
  • làm cho mã dễ đọc hơn
  • Các chức năng và phương thức đó
  • Các đối tượng có thể thuộc về

Sau một đường vòng ngắn vào một số bạn sẽ thấy. Bạn có thể tìm thấy các ví dụ về mã từ phần này tại đây

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

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

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

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

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

Cuối cùng,

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

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

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

Trình tự và ánh xạ

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28,
String thing;
thing = "Hello";
07 và
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39, việc thêm gợi ý loại dễ dàng như sử dụng chính loại đó

>>>

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

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

>>>

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

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62. Các loại này thêm cú pháp để chỉ định các loại phần tử của các loại tổng hợp. Bạn có thể viết như sau

>>>

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

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

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

Mô-đun

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

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

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

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 vào đối số tùy chọn
String thing;
thing = "Hello";
51

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

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

String thing;
thing = "Hello";
52 cho n-tuple

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

String thing;
thing = "Hello";
53

Trong nhiều trường hợp, các chức năng của bạn sẽ mong đợi một số loại và không thực sự quan tâm đó là danh sách hay bộ. Trong những trường hợp này, bạn nên sử dụng

String thing;
thing = "Hello";
54 khi chú thích đối số hàm

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

Sử dụng

String thing;
thing = "Hello";
55 là một ví dụ về cách sử dụng kiểu gõ vịt. Một
String thing;
thing = "Hello";
55 là bất cứ thứ gì hỗ trợ
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 và
String thing;
thing = "Hello";
58, không phụ thuộc vào loại thực tế của nó

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

Nhập bí danh

Gợi ý loại có thể trở nên khá xiên xẹo khi làm việc với các loại lồng nhau như cỗ bài. You may need to stare at

String thing;
thing = "Hello";
48 a bit before figuring out that it matches our representation of a deck of cards

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

String thing;
thing = "Hello";
23

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

Điều đó thật kinh khủng

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

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

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

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

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

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

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

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

>>>

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

Lưu ý rằng khi in

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

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

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

String thing;
thing = "Hello";
67

>>>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Bạn sẽ sớm thấy một cách tốt hơn. First though, let’s have a more theoretical look at the Python type system, and the special role

String thing;
thing = "Hello";
79 plays

Loại lý thuyết

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

tiểu loại

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

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

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

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

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

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

String thing;
thing = "Hello";
97 và
String thing;
thing = "Hello";
98. Loại
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 chỉ nhận hai giá trị. Thông thường, chúng được ký hiệu là
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
40 và
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
33, nhưng những tên này chỉ là bí danh cho các giá trị số nguyên lần lượt là
>>> class TheHobbit:
..     def __len__(self):
..         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
02 và
>>> class TheHobbit:
..     def __len__(self):
..         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
03

>>>

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 là một kiểu con của
String thing;
thing = "Hello";
35

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

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

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

Các kiểu con có phần nào 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)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 là một kiểu con của
String thing;
thing = "Hello";
35 bởi vì
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 là một lớp con của
String thing;
thing = "Hello";
35. Tuy nhiên, cũng có những kiểu con không tương ứng với lớp con. Ví dụ:
String thing;
thing = "Hello";
35 là một kiểu con của
String thing;
thing = "Hello";
07, nhưng
String thing;
thing = "Hello";
35 không phải là một lớp con của
String thing;
thing = "Hello";
07

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

Covariant, Contravariant, và Invariant

Điều gì xảy ra khi bạn sử dụng các kiểu con bên trong các kiểu tổng hợp? . Điều này trở nên nhanh chóng về mặt kỹ thuật, vì vậy hãy chỉ đưa ra một vài ví dụ

  • >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    16 là hiệp phương sai. Điều này có nghĩa là nó duy trì phân cấp loại của các loại mục của nó.
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    14 là kiểu con của
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    15 vì
    >>> thing = "Hello"
    >>> type(thing)
    <class 'str'>
    
    >>> thing = 28.1
    >>> type(thing)
    <class 'float'>
    
    39 là kiểu con của
    String thing;
    thing = "Hello";
    
    35

  • >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    21 là bất biến. Các kiểu bất biến không đảm bảo về các kiểu con. Mặc dù tất cả các giá trị của
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    22 đều là giá trị của
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    23, nhưng bạn có thể nối thêm ____8_______35 vào _____16_______23 chứ không phải _______16_______22. Nói cách khác, điều kiện thứ hai cho các kiểu con không thỏa mãn và
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    22 không phải là kiểu con của
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    23

  • >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    29 là mâu thuẫn trong 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 thức hoạt động của
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    29 , nhưng bây giờ hãy nghĩ về
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    31 như một hàm với đối số duy nhất của nó là kiểu
    String thing;
    thing = "Hello";
    
    87. Một ví dụ về
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    33 là hàm
    >>> class TheHobbit:
    ..     def __len__(self):
    ..         return 95022
    ...
    >>> the_hobbit = TheHobbit()
    >>> len(the_hobbit)
    95022
    
    34 được định nghĩa ở trên. Ngược lại có nghĩa là nếu một chức năng hoạt động trên
    >>> thing = "Hello"
    >>> type(thing)
    <class 'str'>
    
    >>> thing = 28.1
    >>> type(thing)
    <class 'float'>
    
    39 được mong đợi, thì một chức năng hoạt động trên
    String thing;
    thing = "Hello";
    
    35 sẽ được chấp nhận

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

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

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

String thing;
thing = "Hello";
79

Bằng cách nào đó,

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

Loại

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

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

String thing;
thing = "Hello";
79

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

String thing;
thing = "Hello";
79 để quay trở lại kiểu nhập độ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 hỗn hợp. Chẳng hạn, một từ điển có các khóa chuỗi có thể lấy bất kỳ loại nào làm 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
50

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

String thing;
thing = "Hello";
79 thì trình kiểm tra kiểu tĩnh sẽ không thực hiện bất kỳ kiểu 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. Nhớ lại rằng bạn đang cố chú thích hàm

String thing;
thing = "Hello";
72 chung

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

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

String thing;
thing = "Hello";
79 là bạn đang mất thông tin loại một cách không cần thiết. You know that if you pass a list of strings to
String thing;
thing = "Hello";
72, it will return a string. Dưới đây, bạn sẽ thấy cách thể hiện điều này bằng cách sử dụng các biến kiểu, cũng như cách làm việc với

  • Lập luận với

Loại biến

Biến kiểu là một biến đặc biệt có thể nhận bất kỳ kiểu nào, tùy thuộc vào tình huống

Hãy tạo một biến kiểu sẽ gói gọn hành vi của

String thing;
thing = "Hello";
72 một cách hiệu quả

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

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

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
57 từ mô-đun
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62. Khi được sử dụng, một biến loại bao gồm 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
59 bây giờ là một
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28

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

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

Hãy xem xét một vài ví dụ khác

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

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28 và
String thing;
thing = "Hello";
35, nhưng còn hai ví dụ cuối cùng thì sao?

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

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

Như bạn đã thấy,

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
39 là một kiểu con của
String thing;
thing = "Hello";
35, một lần nữa là một kiểu con của
String thing;
thing = "Hello";
07. Vì vậy, trong ví dụ thứ ba, giá trị trả về của
String thing;
thing = "Hello";
72 được đảm bảo là thứ có thể được coi là một
String thing;
thing = "Hello";
07. Trong ví dụ trước, không có mối quan hệ kiểu con nào giữa
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28 và
String thing;
thing = "Hello";
35, 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 gây ra lỗi loại. Có cách nào để báo cho trình kiểm tra loại biết rằng

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

Bạn có thể hạn chế các biến kiểu bằng cách liệt kê các kiểu được chấp nhận

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

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

Bây giờ

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

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28 hoặc
String thing;
thing = "Hello";
07 và Mypy sẽ lưu ý rằng ví dụ cuối cùng là một lỗi

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

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

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

String thing;
thing = "Hello";
07 mặc dù danh sách đầu vào chỉ chứa
String thing;
thing = "Hello";
35 đối tượng. Điều này là do
>>> class TheHobbit:
..     def __len__(self):
..         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
63 bị hạn chế đối với chuỗi và số float và
String thing;
thing = "Hello";
35 là một kiểu con của
String thing;
thing = "Hello";
07

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

String thing;
thing = "Hello";
72 cho
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28 và
String thing;
thing = "Hello";
61

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

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

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

String thing;
thing = "Hello";
55 đạ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";
55 có thể được coi là một loại vịt, vì nó có thể là bất kỳ đối tượng nào có triển khai
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
21 và
String thing;
thing = "Hello";
58

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

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

Nhớ lại ví dụ sau từ

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 có thể trả về độ dài của bất kỳ đối tượng nào đã triển khai phương thức
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
21. Làm cách nào chúng ta có thể thêm các gợi ý loại vào
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 và đặc biệt là đối số
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
26?

Câu trả lời ẩn đằng sau phân nhóm cấu trúc thuật ngữ nghe có vẻ hàn lâm. Một cách để phân loại các hệ thống loại là xem chúng là danh nghĩa hay cấu trúc.

  • 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 đó có thể sử dụng

    String thing;
    thing = "Hello";
    
    35 thay cho
    String thing;
    thing = "Hello";
    
    07 vì mối quan hệ loại phụ của chúng

  • In a 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
    
    93 that includes all instances that define
    >>> thing = "Hello"
    >>> type(thing)
    <class 'str'>
    
    >>> thing = 28.1
    >>> type(thing)
    <class 'float'>
    
    21, irrespective of their nominal type

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
21 fulfill the
>>> class TheHobbit:
..     def __len__(self):
..         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
96 protocol. We can therefore annotate
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 as follows

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

Other defined in the

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
62 module include
>>> class TheHobbit:
..     def __len__(self):
..         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
99,
def len(obj):
    return obj.__len__()
00,
def len(obj):
    return obj.__len__()
01, and
def len(obj):
    return obj.__len__()
02

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

def len(obj):
    return obj.__len__()
03 and defining the function signatures (with empty function bodies) that the protocol expects. The following example shows how
>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
20 and
>>> class TheHobbit:
..     def __len__(self):
..         return 95022
...
>>> the_hobbit = TheHobbit()
>>> len(the_hobbit)
95022
93 could have been implemented

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

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

def len(obj):
    return obj.__len__()
06 module. This module must be explicitly installed from PyPI by doing
def len(obj):
    return obj.__len__()
07

The def len(obj): return obj.__len__() 08 Type

A common pattern in Python is to use

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

In the card example, the

String thing;
thing = "Hello";
73 function uses
String thing;
thing = "Hello";
67 as a sentinel value for
def len(obj):
    return obj.__len__()
12 saying that if no start player is given it should be chosen randomly

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

The challenge this creates for type hinting is that in general

def len(obj):
    return obj.__len__()
12 should be a string. However, it may also take the special non-string value
String thing;
thing = "Hello";
67

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

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

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

The

def len(obj):
    return obj.__len__()
08 type simply says that a variable either has the type specified or is
String thing;
thing = "Hello";
67. An equivalent way of specifying the same would be using the
def len(obj):
    return obj.__len__()
18 type.
def len(obj):
    return obj.__len__()
19

Note that when using either

def len(obj):
    return obj.__len__()
08 or
def len(obj):
    return obj.__len__()
18 you must take care that the variable has the correct type when you operate on it. This is done in the example by testing whether
def len(obj):
    return obj.__len__()
22. Không làm như vậy sẽ gây ra cả lỗi kiểu tĩnh cũng như lỗi thời gian chạy có thể xảy ra

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

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

def len(obj):
    return obj.__len__()
12 is
String thing;
thing = "Hello";
67

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

Note. The use of

String thing;
thing = "Hello";
67 for optional arguments is so common that Mypy handles it automatically. Mypy assumes that a default argument of
String thing;
thing = "Hello";
67 indicates an optional argument even if the type hint does not explicitly say so. You could have used the following

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

If you don’t want Mypy to make this assumption you can turn it off with the

def len(obj):
    return obj.__len__()
27 command line option

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

Example. The Object(ive) of the Game

Let’s rewrite the card game to be more object-oriented. This will allow us to discuss how to properly annotate classes and methods

A more or less direct translation of our card game into code that uses classes for

String thing;
thing = "Hello";
61,
String thing;
thing = "Hello";
62,
def len(obj):
    return obj.__len__()
30, and
def len(obj):
    return obj.__len__()
31 looks something like the following

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

Now let’s add types to this code

Type Hints for Methods

First of all type hints for methods work much the same as type hints for functions. The only difference is that the

def len(obj):
    return obj.__len__()
32 argument need not be annotated, as it always will be a class instance. The types of the
String thing;
thing = "Hello";
61 class are easy to add

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

Note that the

def len(obj):
    return obj.__len__()
34 method always should have
String thing;
thing = "Hello";
67 as its return type

Classes as Types

There is a correspondence between classes and types. For example, all instances of the

String thing;
thing = "Hello";
61 class together form the
String thing;
thing = "Hello";
61 type. To use classes as types you simply use the name of the class

For example, a

String thing;
thing = "Hello";
62 essentially consists of a list of
String thing;
thing = "Hello";
61 objects. You can annotate this as follows

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

Mypy is able to connect your use of

String thing;
thing = "Hello";
61 in the annotation with the definition of the
String thing;
thing = "Hello";
61 class

This doesn’t work as cleanly though when you need to refer to the class currently being defined. For example, the

def len(obj):
    return obj.__len__()
42 class method returns an object with type
String thing;
thing = "Hello";
62. However, you can’t simply add
def len(obj):
    return obj.__len__()
44 as the
String thing;
thing = "Hello";
62 class is not yet fully defined

Instead, you are allowed to use string literals in annotations. These strings will only be evaluated by the type checker later, and can therefore contain self and forward references. The

def len(obj):
    return obj.__len__()
46 method should use such string literals for its types

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

Note that the

def len(obj):
    return obj.__len__()
30 class also will reference the
String thing;
thing = "Hello";
62 class. This is however no problem, since
String thing;
thing = "Hello";
62 is defined before
def len(obj):
    return obj.__len__()
30

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

Usually annotations are not used at runtime. This has given wings to the idea of postponing the evaluation of annotations. Instead of evaluating annotations as Python expressions and storing their value, the proposal is to store the string representation of the annotation and only evaluate it when needed

Chức năng như vậy được lên kế hoạch để trở thành tiêu chuẩn trong Python 4 vẫn còn là thần thoại. 0. However, in Python 3. 7 and later, forward references are available through a

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

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

With the

def len(obj):
    return obj.__len__()
51 import you can use
String thing;
thing = "Hello";
62 instead of
def len(obj):
    return obj.__len__()
54 even before
String thing;
thing = "Hello";
62 is defined

Returning def len(obj): return obj.__len__() 32 or def len(obj): return obj.__len__() 57

As noted, you should typically not annotate the

def len(obj):
    return obj.__len__()
32 or
def len(obj):
    return obj.__len__()
57 arguments. Một phần, điều này là không cần thiết vì
def len(obj):
    return obj.__len__()
32 trỏ đến một thể hiện của lớp, vì vậy nó sẽ có kiểu của lớp. Trong ví dụ về
String thing;
thing = "Hello";
61,
def len(obj):
    return obj.__len__()
32 có kiểu ngầm định là
String thing;
thing = "Hello";
61. Ngoài ra, việc thêm loại này một cách rõ ràng sẽ rất cồng kềnh vì lớp chưa được xác định. Bạn sẽ phải sử dụng cú pháp chuỗi ký tự,
def len(obj):
    return obj.__len__()
64

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__()
32 hoặc
def len(obj):
    return obj.__len__()
57. Xem xét điều gì sẽ xảy ra nếu bạn có một siêu lớp mà các lớp khác kế thừa từ đó và có các phương thức trả về
def len(obj):
    return obj.__len__()
32 hoặc
def len(obj):
    return obj.__len__()
57

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

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

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

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

def len(obj):
    return obj.__len__()
69 và
def len(obj):
    return obj.__len__()
70 sẽ trả về một
def len(obj):
    return obj.__len__()
71 nhưng chú thích nói rằng chúng trả về một
def len(obj):
    return obj.__len__()
72

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__()
32 hoặc loại đối tượng của
def len(obj):
    return obj.__len__()
57. Điều này có thể được thực hiện bằng cách sử dụng các biến kiểu theo dõi những gì thực sự được chuyển đến
def len(obj):
    return obj.__len__()
32 và
def len(obj):
    return obj.__len__()
57

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
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__()
    
    77 được sử dụng để biểu thị rằng các giá trị trả về có thể là thể hiện của các lớp con của
    def len(obj):
        return obj.__len__()
    
    72

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

    def len(obj):
        return obj.__len__()
    
    72 là giới hạn trên của
    def len(obj):
        return obj.__len__()
    
    77. Chỉ định
    def len(obj):
        return obj.__len__()
    
    81 có nghĩa là
    def len(obj):
        return obj.__len__()
    
    77 sẽ chỉ là
    def len(obj):
        return obj.__len__()
    
    72 hoặc một trong các phân lớp 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__()
    
    84 là kiểu gõ tương đương với ____0_______13. 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__() 86 và def len(obj): return obj.__len__() 87

Trong 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 sau tên của chương trình

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

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

def len(obj):
    return obj.__len__()
88 đến
def len(obj):
    return obj.__len__()
89 khi nó được khởi tạo. Phương thức
def len(obj):
    return obj.__len__()
34 sử dụng
def len(obj):
    return obj.__len__()
91 để đóng gói các tên đã cho vào một bộ dữ liệu

Về chú thích loại. mặc dù

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

>>> thing = 28.1
>>> type(thing)
<class 'float'>
28 chứ không phải
def len(obj):
    return obj.__len__()
94

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

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

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

Có thể gọi

Hàm là đố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 hàm làm đối số cho các hàm khác. Điều đó cũng có nghĩa là bạn cần có thể thêm các gợi ý kiểu đại diện cho các chức năng

Hàm, cũng như lambda, phương thức và lớp, là. Các loại đối số và giá trị trả về cũng thường được biểu diễn. Chẳng hạn,

def len(obj):
    return obj.__len__()
97 đại diện cho một hàm có ba đối số với các loại lần lượt là
def len(obj):
    return obj.__len__()
98,
def len(obj):
    return obj.__len__()
99 và
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
00. Kiểu trả về của hàm là
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
01

Trong ví dụ sau, hàm

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
02 gọi một hàm đã cho hai lần và in các giá trị trả về

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

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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
03 cho
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
02 trên dòng 5. Nó nói rằng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
03 phải là một đối số có thể gọi được với một đối số chuỗi, điều đó cũng trả về một chuỗi. Một ví dụ về khả năng gọi như vậy là
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
06 được xác định trên dòng 9

Hầu hết các loại có thể gọi được 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 kiểm tra và

Ví dụ. trái tim

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

  • Bốn người chơi chơi với mỗi người 13 lá bài

  • Người chơi cầm ♣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 bộ đồ hàng đầu nếu có thể

  • Người chơi có quân bài cao nhất trong bộ bài dẫn đầu sẽ thắng mẹo và trở thành người chơi bắt đầu trong lượt tiếp theo

  • Người chơi không thể dẫn trước với ♡ cho đến khi ♡ đã được chơi trong một trò lừa trước đó

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

    • 13 điểm cho ♠Q
    • 1 điểm cho mỗi ♡
  • Một trò chơi kéo dài nhiều vòng, cho đến khi một người chơi có 100 điểm trở lên. Người chơi có ít điểm nhất sẽ 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 gõ mới trong ví dụ này mà bạn chưa thấy. Do đó, chúng tôi sẽ không xem xét chi tiết mã này mà để nó làm ví dụ về mã chú thích

Mã nguồn cho trò chơi bài HeartsHiển thị/Ẩn

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

>>> print(headline("python type checking", align="left"))
Python Type Checking
--------------------
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

    def len(obj):
        return obj.__len__()
    
    18 hoặc biến loại, bạn có thể sử dụng trình trang trí
    def headline(text, align=True):
        if align:
            return f"{text.title()}\n{'-' * len(text)}"
        else:
            return f" {text.title()} ".center(50, "o")
    
    08. Xem
    def headline(text, align=True):
        if align:
            return f"{text.title()}\n{'-' * len(text)}"
        else:
            return f" {text.title()} ".center(50, "o")
    
    09 để biết ví dụ và 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 headline(text, align=True):
        if align:
            return f"{text.title()}\n{'-' * len(text)}"
        else:
            return f" {text.title()} ".center(50, "o")
    
    10 ở bất cứ đâu mong đợi một
    def len(obj):
        return obj.__len__()
    
    30

  • Khi một lớp con hiện thực lại một phương thức từ một lớp cha, các chú thích kiểu phải khớp với. Xem

    def headline(text, align=True):
        if align:
            return f"{text.title()}\n{'-' * len(text)}"
        else:
            return f" {text.title()} ".center(50, "o")
    
    12 để biết ví dụ

Khi bắt đầu trò chơi, bạn điều khiển người chơi đầu tiên. Nhập số để chọn thẻ để chơi. Sau đây là một ví dụ về cách chơi trò chơi, với các dòng được đánh dấu cho biết nơi người chơi đưa ra lựa chọn

$ pip install mypy
0

Kiểm tra loại tĩnh

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

Dự án Mypy

Mypy đã được bắt đầu bởi Jukka Lehtosalo trong thời gian tiến sĩ của mình. D. học tại Cambridge khoảng năm 2012. Mypy ban đầu được hình dung là một biến thể Python với kiểu gõ động và tĩnh liền mạch. Xem các slide của Jukka từ PyCon Phần Lan 2012 để biết ví dụ về tầm nhìn ban đầu của Mypy

Hầu hết những ý tưởng ban đầu đó vẫn đóng một vai trò quan trọng trong dự án Mypy. Trên thực tế, khẩu hiệu “Gõ động và tĩnh liền mạch” vẫn hiển thị nổi bật trên trang chủ của Mypy và mô tả rõ động cơ thúc đẩy sử dụng các gợi ý kiểu trong Python

Thay đổi lớn nhất kể từ năm 2012 là Mypy không còn là một biến thể của Python. Trong các phiên bản đầu tiên, Mypy là một ngôn ngữ độc lập tương thích với Python ngoại trừ các khai báo kiểu của nó. Theo gợi ý của Guido van Rossum, Mypy đã được viết lại để sử dụng chú thích thay thế. Hôm nay Mypy là trình kiểm tra kiểu tĩnh cho mã Python thông thường

Chạy Mypy

Trước khi chạy Mypy lần đầu tiên, bạn phải cài đặt chương trình. Điều này được thực hiện dễ dàng nhất bằng cách sử dụng

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
52

$ pip install mypy

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

$ pip install mypy
2

Chạy Mypy trên tệp Python

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
14 của bạn sẽ kiểm tra lỗi loại mà không thực sự thực thi mã

Có nhiều tùy chọn có sẵn khi gõ kiểm tra mã của bạn. Vì Mypy vẫn đang được phát triển rất tích cực, các tùy chọn dòng lệnh có thể thay đổi giữa các phiên bản. Bạn nên tham khảo phần trợ giúp của Mypy để xem cài đặt nào là mặc định trên phiên bản của bạn

$ pip install mypy
3

Ngoài ra, có rất nhiều thông tin

Hãy xem xét một số tùy chọn phổ biến nhất. Trước hết, nếu bạn đang sử dụng các gói của bên thứ ba không có gợi ý loại, bạn có thể muốn tắt tiếng các cảnh báo của Mypy về những. Điều này có thể được thực hiện với tùy chọn

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

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

$ pip install mypy
4

Lưu ý rằng

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
16 chỉ có trong phiên bản 1. 15 trở lên của Numpy. Chạy ví dụ này sẽ in một số số ra bàn điều khiển

$ pip install mypy
5

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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
17 được chú thích bằng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
18 trên dòng 5, vì chúng tôi muốn in cosin của một dãy số đầy đủ

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

$ pip install mypy
6

Những cảnh báo này có thể không có ý nghĩa ngay lập tức đối với bạn, nhưng bạn sẽ sớm tìm hiểu về nó. Về cơ bản, bạn có thể đọc các cảnh báo khi Mypy nói rằng gói Numpy không chứa các gợi ý về loại

Trong hầu hết các trường hợp, các gợi ý loại bị thiếu trong các gói của bên thứ ba không phải là điều bạn muốn làm phiền, vì vậy bạn có thể tắt các tin nhắn này

$ pip install mypy
7

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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
19, Mypy sẽ. Tuy nhiên, điều này có thể hơi nặng tay vì nó cũng bỏ qua các lỗi thực tế, chẳng hạn như viết sai chính tả tên của một gói

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

Trong một ví dụ đơn giản như ví dụ trên, bạn có thể tắt tiếng cảnh báo

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
20 bằng cách thêm một nhận xét loại vào dòng chứa nội dung nhập

$ pip install mypy
8

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
21 theo nghĩa đen bảo Mypy bỏ qua việc nhập Numpy

Nếu bạn có nhiều tệp, việc theo dõi những lần nhập nào cần bỏ qua trong tệp cấu hình có thể dễ dàng hơn. Mypy đọc một tệp có tên là

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
22 trong thư mục hiện tại nếu nó hiện diện. Tệp cấu hình này phải chứa một phần có tên là
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
23 và có thể chứa các phần cụ thể của mô-đun có dạng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
24

Tệp cấu hình sau sẽ bỏ qua gợi ý loại Numpy bị thiếu

$ pip install mypy
9

Có nhiều tùy chọn có thể được chỉ định trong tệp cấu hình. Cũng có thể chỉ định một tệp cấu hình chung. Xem tài liệu để cho biết thêm thông tin chi tiết

Thêm sơ khai

Gợi ý loại có sẵn cho tất cả các gói trong thư viện chuẩn Python. Tuy nhiên, nếu bạn đang sử dụng các gói của bên thứ ba, bạn đã thấy rằng tình huống có thể khác

Ví dụ sau sử dụng gói Parse để thực hiện phân tích cú pháp văn bản đơn giản. Để làm theo, trước tiên bạn nên cài đặt Parse

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
00

Phân tích cú pháp có thể được sử dụng để nhận dạng các mẫu đơn giản. Đây là một chương trình nhỏ cố gắng hết sức để tìm ra tên của bạn

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
01

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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
25 được gọi ở dòng 14 để cố gắng tìm tên dựa trên một trong các mẫu được liệt kê ở dòng 7-11

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
02

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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
26, nhưng chương trình chỉ ra rằng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
27 không phải là một phần tên của tôi

Hãy thêm một lỗi nhỏ vào chương trình và xem liệu Mypy có thể giúp chúng tôi phát hiện ra nó không. Thay đổi dòng 16 từ

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
28 thành
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
29. Điều này sẽ 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")
30 thay vì chuỗi chứa tên

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
03

Mypy in một lỗi tương tự như lỗi bạn đã thấy trong phần trước. Nó không biết về gói

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
25. Bạn có thể thử bỏ qua việc nhập

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
04

Thật không may, bỏ qua quá trình nhập có nghĩa là Mypy không có cách nào phát hiện ra lỗi trong chương trình của chúng tôi. Một giải pháp tốt hơn là thêm các gợi ý loại vào chính gói Parse. Vì Parse là nguồn mở, bạn thực sự có thể thêm các loại vào mã nguồn và gửi yêu cầu kéo

Ngoài ra, bạn có thể thêm các loại trong tệp sơ khai. Tệp sơ khai là một tệp văn bản chứa chữ ký của các phương thức và hàm, nhưng không chứa các triển khai của chúng. Chức năng chính của chúng là thêm các gợi ý kiểu vào mã mà bạn không thể thay đổi vì lý do nào đó. Để hiển thị cách thức hoạt động của nó, chúng tôi sẽ thêm một số sơ khai cho gói Parse

Trước hết, bạn nên đặt tất cả các tệp sơ khai của mình vào trong một thư mục chung và đặt biến môi trường

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
32 để 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")
32 như sau

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
05

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")
34 của mình. Trên Windows, bạn có thể nhấp vào menu bắt đầu và tìm kiếm các biến môi trường để đặt
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
32

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")
36. 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")
37. Để trống tập tin này ngay bây giờ. Sau đó chạy lại Mypy

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
06

Nếu bạn đã thiết lập mọi thứ chính xác, bạn sẽ thấy thông báo lỗi mới này. Mypy sử dụng tệp

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
36 mới để tìm ra chức năng nào có sẵn trong gói
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
25. Vì tệp sơ khai trống, Mypy giả định rằng
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
40 không tồn tại và sau đó đưa ra lỗi mà bạn thấy ở trên

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

def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
25. Thay vào đó, nó hiển thị gợi ý loại mà bạn cần thêm để Mypy nhập. 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")
40

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
07

Dấu chấm lửng

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

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

>>> thing = "Hello"
>>> type(thing)
<class 'str'>

>>> thing = 28.1
>>> type(thing)
<class 'float'>
08

Điều này trỏ thẳng đến 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")
45 chứ không phải chuỗi tên. Sửa lại
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
29 thành
def headline(text, align=True):
    if align:
        return f"{text.title()}\n{'-' * len(text)}"
    else:
        return f" {text.title()} ".center(50, "o")
28 chạy Mypy lại thấy sướng

đánh máy

Bạn đã biết cách sử dụng sơ khai để thêm gợi ý loại mà không thay đổi chính mã nguồn. Trong phần trước, chúng tôi đã thêm một số gợi ý loại vào gói Parse của bên thứ ba. Bây giờ, sẽ không hiệu quả lắm nếu mọi người cần tạo các tệp sơ khai của riêng họ cho tất cả các gói của bên thứ ba mà họ đang sử dụng

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

Bạn cũng có thể đóng góp các gợi ý về kiểu chữ cho Typeshed. Tuy nhiên, trước tiên hãy đảm bảo xin phép chủ sở hữu gói, đặc biệt là vì họ có thể đang làm việc để thêm gợi ý loại vào chính mã nguồn—đó là

Trình kiểm tra loại tĩnh khác

Trong hướng dẫn này, chúng tôi chủ yếu tập trung vào kiểm tra kiểu bằng Mypy. Tuy nhiên, có các trình kiểm tra kiểu tĩnh khác trong hệ sinh thái Python

Trình chỉnh sửa đi kèm với trình kiểm tra loại riêng đi kèm. Nếu bạn đang sử dụng PyCharm để viết mã Python của mình, nó sẽ tự động được kiểm tra loại

Facebook đã phát triển Pyre. Một trong những mục tiêu đã nêu của nó là nhanh chóng và hiệu quả. Mặc dù có một số khác biệt, các chức năng của Pyre hầu như tương tự như Mypy. Xem tài liệu nếu bạn muốn dùng thử Pyre

Hơn nữa, Google đã tạo Pytype. Trình kiểm tra loại này cũng hoạt động gần giống như Mypy. Ngoài việc kiểm tra mã được chú thích, Pytype còn có một số hỗ trợ để chạy kiểm tra loại trên mã không được chú thích và thậm chí tự động thêm chú thích vào mã. Xem tài liệu bắt đầu nhanh để biết thêm thông tin

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

Lưu ý cuối cùng, bạn cũng có thể sử dụng các gợi ý loại trong thời gian chạy trong quá trình thực thi chương trình Python của mình. Kiểm tra loại thời gian chạy có thể sẽ không bao giờ được hỗ trợ nguyên bản trong Python

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

String thing;
thing = "Hello";
10 và bạn có thể sử dụng chúng để thực hiện kiểm tra loại nếu muốn. Trước khi bạn chạy và viết gói của riêng mình để thực thi các loại, bạn nên biết rằng đã có một số gói làm việc này cho bạn. Hãy xem Enforce, Pydantic hoặc Pytypes để biết một số ví dụ

Một cách sử dụng khác của gợi ý loại là để dịch mã Python của bạn sang C và biên dịch nó để tối ưu hóa. Dự án Cython phổ biến sử dụng ngôn ngữ C/Python lai để viết mã Python được nhập tĩnh. Tuy nhiên, kể từ phiên bản 0. 27 Cython cũng đã hỗ trợ các chú thích kiểu. Gần đây, dự án Mypyc đã có sẵn. Mặc dù chưa sẵn sàng để sử dụng chung, nhưng nó có thể biên dịch một số loại mã Python được chú thích thành các tiện ích mở rộng C

Phần kết luận

Gõ gợi ý trong Python là một tính năng rất hữu ích mà bạn có thể vui vẻ sống mà không cần. Gợi ý nhập không giúp bạn có khả năng viết bất kỳ mã nào mà bạn không thể viết nếu không sử dụng gợi ý nhập. Thay vào đó, sử dụng các gợi ý kiểu giúp bạn dễ dàng suy luận về mã hơn, tìm ra các lỗi tinh vi và duy trì một kiến ​​trúc rõ ràng

Trong hướng dẫn này, bạn đã học cách gợi ý kiểu hoạt động trong Python và cách gõ dần dần giúp kiểm tra kiểu trong Python linh hoạt hơn so với nhiều ngôn ngữ khác. Bạn đã thấy một số ưu và nhược điểm của việc sử dụng gợi ý kiểu và cách chúng có thể được thêm vào mã bằng cách sử dụng chú thích hoặc chú thích kiểu. Cuối cùng, bạn đã thấy nhiều kiểu khác nhau mà Python hỗ trợ, cũng như cách thực hiện kiểm tra kiểu tĩnh

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

Đánh dấu là đã hoàn thành

Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Kiểm tra loại Python

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

Gửi cho tôi thủ thuật Python »

Giới thiệu về Geir Arne Hjelle

Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì
Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

Geir Arne là một Pythonista cuồng nhiệt và là thành viên của nhóm hướng dẫn Real Python

» Thông tin thêm về Geir Arne


Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

Aldren

Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

Brad

Hai kiểu con bên trong của dữ liệu chuỗi trong python Lớp 11 là gì

Joanna

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Chuyên gia Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Các kiểu con của chuỗi là gì?

Các kiểu dữ liệu chuỗi là CHAR , VARCHAR , BINARY , VARBINARY , BLOB , TEXT , ENUM và SET .

Cấu trúc bên trong của chuỗi Python là gì?

Kiểu dữ liệu chuỗi trong Python lớp 11 là gì?

Kiểu dữ liệu Chuỗi trong python cho phép bạn giữ bất kỳ ký tự hợp lệ nào (số chẵn) vào một tập hợp dấu ngoặc kép . e. g. 'aim1', “abc123”

Có bao nhiêu loại chuỗi trong Python?

Trả lời. Python hỗ trợ hai loại chuỗi — Chuỗi một dòng và Chuỗi nhiều dòng. Chuỗi một dòng được đặt trong dấu ngoặc đơn hoặc dấu ngoặc kép và kết thúc bằng một dòng. Chuỗi nhiều dòng lưu trữ nhiều dòng văn bản và được đặt trong ba dấu ngoặc kép.