TL; DR : nếu bạn đang sử dụng Python 4.0 thì nó chỉ hoạt động. Kể từ hôm nay (2019) trong 3.7+, bạn phải bật tính năng này bằng cách sử dụng câu lệnh tương lai ( from __future__ import annotations
) - cho Python 3.6 trở xuống sử dụng chuỗi.
Tôi đoán bạn có ngoại lệ này:
NameError: name 'Position' is not defined
Điều này là do Position
phải được xác định trước khi bạn có thể sử dụng nó trong một chú thích trừ khi bạn đang sử dụng Python 4.
Python 3.7+: from __future__ import annotations
Python 3.7 giới thiệu PEP 563: hoãn đánh giá các chú thích . Một mô-đun sử dụng câu lệnh trong tương lai from __future__ import annotations
sẽ tự động lưu các chú thích dưới dạng chuỗi:
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
Điều này được lên kế hoạch để trở thành mặc định trong Python 4.0. Vì Python vẫn là một ngôn ngữ được gõ động nên không có kiểm tra kiểu nào được thực hiện trong thời gian chạy, nên gõ chú thích sẽ không có tác động hiệu suất, phải không? Sai lầm! Trước python 3.7, mô-đun gõ được sử dụng là một trong những mô-đun python chậm nhất trong lõi, vì vậy nếu import typing
bạn sẽ thấy hiệu suất tăng gấp 7 lần khi bạn nâng cấp lên 3.7.
Python <3.7: sử dụng chuỗi
Theo PEP 484 , bạn nên sử dụng một chuỗi thay vì chính lớp đó:
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
Nếu bạn sử dụng khung Django thì điều này có thể quen thuộc vì các mô hình Django cũng sử dụng các chuỗi cho các tham chiếu chuyển tiếp (định nghĩa khóa ngoài trong đó mô hình nước ngoài đang self
hoặc chưa được khai báo). Điều này sẽ làm việc với Pycharm và các công cụ khác.
Nguồn
Các phần có liên quan của PEP 484 và PEP 563 , để dành cho bạn chuyến đi:
Chuyển tiếp tài liệu tham khảo
Khi một gợi ý kiểu chứa các tên chưa được xác định, định nghĩa đó có thể được biểu thị dưới dạng một chuỗi ký tự, sẽ được giải quyết sau.
Một tình huống trong đó điều này xảy ra phổ biến là định nghĩa của lớp container, trong đó lớp được định nghĩa xảy ra trong chữ ký của một số phương thức. Ví dụ: đoạn mã sau (bắt đầu triển khai cây nhị phân đơn giản) không hoạt động:
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
Để giải quyết điều này, chúng tôi viết:
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
Chuỗi ký tự phải chứa một biểu thức Python hợp lệ (nghĩa là biên dịch (lit, '', 'eval') phải là một đối tượng mã hợp lệ) và nó sẽ đánh giá không có lỗi khi mô-đun đã được tải đầy đủ. Không gian tên cục bộ và toàn cầu trong đó nó được đánh giá phải là cùng một không gian tên trong đó các đối số mặc định cho cùng một hàm sẽ được đánh giá.
và PEP 563:
Trong Python 4.0, các chú thích hàm và biến sẽ không còn được đánh giá tại thời điểm định nghĩa. Thay vào đó, một dạng chuỗi sẽ được bảo tồn trong __annotations__
từ điển tương ứng . Trình kiểm tra loại tĩnh sẽ thấy không có sự khác biệt trong hành vi, trong khi các công cụ sử dụng chú thích trong thời gian chạy sẽ phải thực hiện đánh giá bị hoãn.
...
Chức năng được mô tả ở trên có thể được kích hoạt bắt đầu từ Python 3.7 bằng cách nhập đặc biệt sau:
from __future__ import annotations
Thay vào đó, những việc mà bạn có thể muốn làm
A. Xác định một hình nộm Position
Trước định nghĩa lớp, đặt một định nghĩa giả:
class Position(object):
pass
class Position(object):
...
Điều này sẽ thoát khỏi NameError
và thậm chí có thể trông ổn:
>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}
Nhưng nó là?
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: False
other is Position: False
B. Khỉ vá để thêm chú thích:
Bạn có thể muốn thử một số phép thuật lập trình meta Python và viết một trình trang trí để vá lỗi định nghĩa lớp để thêm chú thích:
class Position:
...
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
Người trang trí phải chịu trách nhiệm tương đương với điều này:
Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position
Ít nhất thì nó có vẻ đúng:
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: True
other is Position: True
Có lẽ là quá nhiều rắc rối.
Phần kết luận
Nếu bạn đang sử dụng 3.6 trở xuống, hãy sử dụng một chuỗi ký tự chứa tên lớp, trong 3.7 sử dụng from __future__ import annotations
và nó sẽ chỉ hoạt động.