TL; DR : jika Anda menggunakan Python 4.0 itu hanya berfungsi. Mulai hari ini (2019) dalam 3,7+ Anda harus mengaktifkan fitur ini menggunakan pernyataan masa depan (from __future__ import annotations
) - untuk Python 3.6 atau di bawahnya menggunakan string.
Saya kira Anda mendapatkan pengecualian ini:
NameError: name 'Position' is not defined
Hal ini karena Position
harus ditentukan sebelum Anda dapat menggunakannya dalam anotasi kecuali Anda menggunakan Python 4.
Python 3.7+: from __future__ import annotations
Python 3.7 memperkenalkan PEP 563: evaluasi anotasi yang ditunda . Modul yang menggunakan pernyataan di masa mendatang from __future__ import annotations
akan menyimpan anotasi sebagai string secara otomatis:
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
Ini dijadwalkan menjadi default di Python 4.0. Karena Python masih merupakan bahasa yang diketik secara dinamis sehingga tidak ada pemeriksaan tipe yang dilakukan pada saat runtime, mengetik anotasi seharusnya tidak memiliki dampak kinerja, bukan? Salah! Sebelum python 3.7, modul pengetikan digunakan untuk menjadi salah satu modul python paling lambat di inti jadi jika import typing
Anda akan melihat hingga 7 kali peningkatan kinerja ketika Anda meningkatkan ke 3,7.
Python <3.7: gunakan string
Menurut PEP 484 , Anda harus menggunakan string daripada kelas itu sendiri:
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
Jika Anda menggunakan kerangka Django ini mungkin akrab karena model Django juga menggunakan string untuk referensi ke depan (definisi kunci asing di mana model asing adalah self
atau belum dideklarasikan). Ini harus bekerja dengan Pycharm dan alat-alat lainnya.
Sumber
Bagian-bagian PEP 484 dan PEP 563 yang relevan , untuk membantu Anda melakukan perjalanan:
Referensi penerusan
Ketika petunjuk jenis berisi nama-nama yang belum didefinisikan, definisi tersebut dapat dinyatakan sebagai string literal, untuk diselesaikan nanti.
Situasi di mana hal ini terjadi umumnya adalah definisi kelas kontainer, di mana kelas yang didefinisikan terjadi dalam tanda tangan beberapa metode. Sebagai contoh, kode berikut (awal implementasi pohon biner sederhana) tidak berfungsi:
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
Untuk mengatasi ini, kami menulis:
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
Literal string harus berisi ekspresi Python yang valid (yaitu, kompilasi (lit, '', 'eval') harus menjadi objek kode yang valid) dan harus mengevaluasi tanpa kesalahan setelah modul telah dimuat penuh. Namespace lokal dan global yang dievaluasi harus ruang nama yang sama di mana argumen default untuk fungsi yang sama akan dievaluasi.
dan PEP 563:
Dalam Python 4.0, anotasi fungsi dan variabel tidak akan lagi dievaluasi pada waktu definisi. Sebagai gantinya, bentuk string akan disimpan dalam __annotations__
kamus masing-masing . Pemeriksa tipe statis tidak akan melihat perbedaan dalam perilaku, sedangkan alat yang menggunakan anotasi saat runtime harus melakukan evaluasi yang ditunda.
...
Fungsi yang dijelaskan di atas dapat diaktifkan mulai dari Python 3.7 menggunakan impor khusus berikut:
from __future__ import annotations
Hal-hal yang mungkin tergoda untuk Anda lakukan
A. Definisikan boneka Position
Sebelum definisi kelas, tempatkan definisi dummy:
class Position(object):
pass
class Position(object):
...
Ini akan menghilangkan NameError
dan bahkan mungkin terlihat OK:
>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}
Tetapi apakah itu?
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: False
other is Position: False
B. Kera-tambalan untuk menambahkan anotasi:
Anda mungkin ingin mencoba beberapa sihir pemrograman meta Python dan menulis dekorator ke monyet-patch definisi kelas untuk menambahkan anotasi:
class Position:
...
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
Dekorator harus bertanggung jawab atas hal yang setara ini:
Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position
Setidaknya sepertinya benar:
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: True
other is Position: True
Mungkin terlalu banyak kesulitan.
Kesimpulan
Jika Anda menggunakan 3,6 atau di bawah menggunakan string literal yang berisi nama kelas, gunakan 3,7 from __future__ import annotations
dan itu hanya akan berfungsi.