Saya sarankan membaca PEP 483 dan PEP 484 dan menonton presentasi ini oleh Guido pada Type Hinting.
Singkatnya : Mengisyaratkan mengetik secara literal artinya, Anda mengisyaratkan jenis objek yang Anda gunakan .
Karena sifat dinamis Python, menyimpulkan atau memeriksa jenis objek yang digunakan sangat sulit. Fakta ini menyulitkan pengembang untuk memahami apa yang sebenarnya terjadi dalam kode yang belum mereka tulis dan, yang paling penting, untuk alat pengecekan tipe yang ditemukan di banyak IDE [PyCharm, PyDev datang ke pikiran] yang terbatas karena fakta bahwa mereka tidak memiliki indikator apa pun jenis objeknya. Akibatnya mereka resor untuk mencoba menyimpulkan tipe dengan (seperti yang disebutkan dalam presentasi) sekitar 50% tingkat keberhasilan.
Untuk mengambil dua slide penting dari presentasi Type Hinting:
Mengapa Mengetik Petunjuk?
- Membantu Pemeriksa Jenis: Dengan memberi petunjuk jenis apa yang Anda inginkan objek menjadi pemeriksa jenis dapat dengan mudah mendeteksi jika, misalnya, Anda melewati objek dengan jenis yang tidak diharapkan.
- Membantu dengan dokumentasi: Orang ketiga yang melihat kode Anda akan tahu apa yang diharapkan di mana, ergo, cara menggunakannya tanpa mendapatkannya
TypeErrors
.
- Membantu IDE mengembangkan alat yang lebih akurat dan kuat: Lingkungan Pengembangan akan lebih cocok untuk menyarankan metode yang tepat ketika tahu apa jenis objek Anda. Anda mungkin pernah mengalami ini dengan beberapa IDE di beberapa titik, memukul
.
dan memiliki metode / atribut yang muncul yang tidak didefinisikan untuk objek.
Mengapa menggunakan Pemeriksa Tipe Statis?
- Temukan bug lebih cepat : Ini jelas, saya percaya.
- Semakin besar proyek Anda semakin Anda membutuhkannya : Sekali lagi, masuk akal. Bahasa statis menawarkan kekokohan dan kontrol yang kurang dimiliki bahasa dinamis. Aplikasi Anda yang lebih besar dan lebih kompleks menjadi lebih banyak kontrol dan prediktabilitas (dari aspek perilaku) yang Anda butuhkan.
- Tim besar sudah menjalankan analisis statis : Saya kira ini memverifikasi dua poin pertama.
Sebagai catatan penutup untuk pengantar kecil ini : Ini adalah fitur opsional dan, dari apa yang saya mengerti, ini telah diperkenalkan untuk menuai beberapa manfaat dari pengetikan statis.
Anda umumnya tidak perlu khawatir tentang hal itu dan pasti tidak perlu menggunakannya (terutama dalam kasus di mana Anda menggunakan Python sebagai bahasa scripting tambahan). Seharusnya bermanfaat ketika mengembangkan proyek-proyek besar karena menawarkan ketahanan yang sangat dibutuhkan, kontrol dan kemampuan debugging tambahan .
Ketik Petunjuk dengan mypy :
Untuk membuat jawaban ini lebih lengkap, saya pikir sedikit demonstrasi akan cocok. Saya akan menggunakan mypy
, perpustakaan yang menginspirasi Petunjuk Jenis saat mereka disajikan dalam PEP. Ini terutama ditulis untuk siapa saja yang menabrak pertanyaan ini dan bertanya-tanya harus mulai dari mana.
Sebelum saya melakukannya, izinkan saya mengulangi yang berikut: PEP 484 tidak menegakkan apa pun; itu hanya menetapkan arah untuk penjelasan fungsi dan mengusulkan pedoman untuk bagaimana pemeriksaan tipe dapat / harus dilakukan. Anda dapat membuat anotasi fungsi Anda dan memberi petunjuk sebanyak mungkin hal yang Anda inginkan; skrip Anda akan tetap berjalan terlepas dari keberadaan anotasi karena Python sendiri tidak menggunakannya.
Bagaimanapun, sebagaimana dicatat dalam PEP, tipe-tipe yang mengisyaratkan umumnya harus mengambil tiga bentuk:
- Anotasi fungsi. ( PEP 3107 )
- Stub file untuk modul built-in / pengguna.
# type: type
Komentar khusus yang melengkapi dua bentuk pertama. (Lihat: Apa anotasi variabel dalam Python 3.6? Untuk pembaruan Python 3.6 untuk # type: type
komentar)
Selain itu, Anda ingin menggunakan petunjuk jenis bersamaan dengan typing
modul baru yang diperkenalkan Py3.5
. Di dalamnya, banyak (tambahan) ABC (Abstract Base Classes) didefinisikan bersama dengan fungsi pembantu dan dekorator untuk digunakan dalam pemeriksaan statis. Kebanyakan ABCs
di collections.abc
dimasukkan tapi dalam Generic
bentuk untuk memungkinkan berlangganan (dengan mendefinisikan __getitem__()
metode).
Bagi siapa pun yang tertarik dengan penjelasan yang lebih mendalam tentang ini, mypy documentation
ini ditulis dengan sangat baik dan memiliki banyak sampel kode yang menunjukkan / menggambarkan fungsi pemeriksa mereka; itu pasti layak dibaca.
Anotasi fungsi dan komentar khusus:
Pertama, menarik untuk mengamati beberapa perilaku yang bisa kita dapatkan ketika menggunakan komentar khusus. # type: type
Komentar khusus dapat ditambahkan selama penugasan variabel untuk menunjukkan jenis objek jika seseorang tidak dapat disimpulkan secara langsung. Penugasan sederhana umumnya mudah disimpulkan tetapi yang lain, seperti daftar (yang berkaitan dengan isinya), tidak bisa.
Catatan: Jika kita ingin menggunakan turunan apa pun Containers
dan perlu menentukan konten untuk wadah itu, kita harus menggunakan tipe generik dari typing
modul. Ini mendukung pengindeksan.
# generic List, supports indexing.
from typing import List
# In this case, the type is easily inferred as type: int.
i = 0
# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = [] # type: List[str]
# Appending an int to our list
# is statically not correct.
a.append(i)
# Appending a string is fine.
a.append("i")
print(a) # [0, 'i']
Jika kita menambahkan perintah ini ke file dan menjalankannya dengan juru bahasa kita, semuanya berfungsi dengan baik dan print(a)
hanya mencetak isi daftar a
. The # type
komentar telah dibuang, diperlakukan sebagai komentar polos yang tidak memiliki makna semantik tambahan .
Dengan menjalankan ini dengan mypy
, di sisi lain, kami mendapat respons berikut:
(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
Menunjukkan bahwa daftar str
objek tidak dapat berisi int
, yang, secara statis, adalah suara. Ini dapat diperbaiki dengan mematuhi jenis a
dan hanya menambahkan str
objek atau dengan mengubah jenis konten a
untuk menunjukkan bahwa nilai apa pun dapat diterima (Dilakukan secara intuitif dengan List[Any]
setelah Any
diimpor dari typing
).
Anotasi fungsi ditambahkan dalam formulir param_name : type
setelah setiap parameter dalam tanda tangan fungsi Anda dan tipe pengembalian ditentukan menggunakan -> type
notasi sebelum tanda titik dua fungsi; semua anotasi disimpan dalam __annotations__
atribut untuk fungsi itu dalam bentuk kamus yang praktis. Menggunakan contoh sepele (yang tidak memerlukan jenis tambahan dari typing
modul):
def annotated(x: int, y: str) -> bool:
return x < y
The annotated.__annotations__
atribut sekarang memiliki nilai-nilai berikut:
{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}
Jika kita benar-benar noobie, atau kita terbiasa dengan Py2.7
konsep dan akibatnya tidak mengetahui TypeError
mengintai dalam perbandingan annotated
, kita dapat melakukan pemeriksaan statis lain, menangkap kesalahan dan menyelamatkan kita dari beberapa masalah:
(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")
Antara lain, memanggil fungsi dengan argumen yang tidak valid juga akan ketahuan:
annotated(20, 20)
# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"
Ini pada dasarnya dapat diperluas ke kasus penggunaan apa saja dan kesalahan yang ditangkap meluas lebih jauh dari panggilan dasar dan operasi. Jenis-jenis yang dapat Anda periksa benar-benar fleksibel dan saya hanya memberi sedikit kemungkinan. Melihat typing
modul, PEPs atau mypy
dokumen akan memberi Anda ide yang lebih komprehensif dari kemampuan yang ditawarkan.
File rintisan:
File rintisan dapat digunakan dalam dua kasus berbeda yang tidak saling eksklusif:
- Anda perlu mengetikkan centang pada modul yang Anda tidak ingin langsung mengubah tanda tangan fungsi
- Anda ingin menulis modul dan memeriksa jenis tetapi juga ingin memisahkan anotasi dari konten.
File rintisan apa (dengan ekstensi .pyi
) adalah antarmuka beranotasi dari modul yang Anda buat / ingin gunakan. Mereka berisi tanda tangan dari fungsi yang ingin Anda ketik-periksa dengan tubuh fungsi dibuang. Untuk merasakan hal ini, diberikan satu set tiga fungsi acak dalam sebuah modul bernama randfunc.py
:
def message(s):
print(s)
def alterContents(myIterable):
return [i for i in myIterable if i % 2 == 0]
def combine(messageFunc, itFunc):
messageFunc("Printing the Iterable")
a = alterContents(range(1, 20))
return set(a)
Kita dapat membuat file rintisan randfunc.pyi
, di mana kita dapat menempatkan beberapa batasan jika kita ingin melakukannya. Kelemahannya adalah seseorang yang melihat sumber tanpa rintisan tidak akan benar-benar mendapatkan bantuan anotasi ketika mencoba memahami apa yang seharusnya diteruskan ke mana.
Bagaimanapun, struktur file rintisan cukup sederhana: Tambahkan semua definisi fungsi dengan badan kosong ( pass
diisi) dan berikan penjelasan berdasarkan kebutuhan Anda. Di sini, mari kita asumsikan kita hanya ingin bekerja dengan int
tipe untuk Kontainer kita.
# Stub for randfucn.py
from typing import Iterable, List, Set, Callable
def message(s: str) -> None: pass
def alterContents(myIterable: Iterable[int])-> List[int]: pass
def combine(
messageFunc: Callable[[str], Any],
itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass
The combine
Fungsi memberikan indikasi mengapa Anda mungkin ingin menggunakan anotasi dalam file yang berbeda, mereka beberapa kali mengacaukan kode dan mengurangi keterbacaan (besar tidak-tidak untuk Python). Anda tentu saja bisa menggunakan alias ketik tetapi kadang-kadang membingungkan lebih dari itu membantu (jadi gunakan dengan bijak).
Ini akan membuat Anda terbiasa dengan konsep dasar Tip Petunjuk dalam Python. Meskipun pemeriksa tipe yang digunakan adalah
mypy
Anda harus secara bertahap mulai melihat lebih banyak dari mereka yang muncul, beberapa secara internal di IDE ( PyCharm ,) dan lainnya sebagai modul python standar. Saya akan mencoba dan menambahkan checker tambahan / paket terkait dalam daftar berikut kapan dan jika saya menemukannya (atau jika disarankan).
Dam yang saya tahu :
- Mypy : seperti yang dijelaskan di sini.
- PyType : Oleh Google, menggunakan notasi berbeda dari yang saya kumpulkan, mungkin layak untuk dilihat.
Paket / Proyek Terkait :
- diketik: Repo Python resmi menampung bermacam-macam file rintisan untuk pustaka standar.
The typeshed
proyek sebenarnya adalah salah satu tempat terbaik yang Anda dapat melihat untuk melihat bagaimana jenis mengisyaratkan mungkin digunakan dalam proyek Anda sendiri. Mari kita mengambil sebagai contoh yang __init__
Dunders dari Counter
kelas di yang sesuai .pyi
berkas:
class Counter(Dict[_T, int], Generic[_T]):
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
@overload
def __init__(self, iterable: Iterable[_T]) -> None: ...
Di mana _T = TypeVar('_T')
digunakan untuk mendefinisikan kelas generik . Untuk Counter
kelas kita dapat melihat bahwa ia tidak dapat mengambil argumen di penginisialisasi, mendapatkan satu Mapping
dari jenis apa pun ke int
atau mengambil Iterable
jenis apa pun.
Perhatikan : Satu hal yang saya lupa sebutkan adalah bahwa typing
modul telah diperkenalkan secara sementara . Dari PEP 411 :
Paket sementara mungkin API-nya dimodifikasi sebelum "lulus" menjadi "stabil". Di satu sisi, keadaan ini memberikan paket dengan manfaat menjadi bagian resmi dari distribusi Python. Di sisi lain, tim pengembangan inti secara eksplisit menyatakan bahwa tidak ada janji yang dibuat berkaitan dengan stabilitas API paket, yang dapat berubah untuk rilis berikutnya. Meskipun dianggap sebagai hasil yang tidak mungkin, paket-paket seperti itu bahkan dapat dihapus dari perpustakaan standar tanpa periode penghentian jika kekhawatiran mengenai API atau pemeliharaannya terbukti beralasan.
Jadi bawalah semuanya ke sini dengan sejumput garam; Saya ragu apakah itu akan dihapus atau diubah secara signifikan tetapi orang tidak akan pernah tahu.
** Topik lain sama sekali tetapi valid dalam lingkup type-hints:: PEP 526
Sintaks untuk Anotasi Variabel adalah upaya untuk mengganti # type
komentar dengan memperkenalkan sintaks baru yang memungkinkan pengguna untuk membubuhi keterangan jenis variabel dalam varname: type
pernyataan sederhana .
Lihat Apa anotasi variabel dalam Python 3.6? , seperti yang disebutkan sebelumnya, untuk intro kecil tentang ini.