Perbedaan antara mendefinisikan pengetikan.Dikt dan dikt?

105

Saya berlatih menggunakan petunjuk tipe di Python 3.5. Salah satu kolega saya menggunakan typing.Dict:

import typing


def change_bandwidths(new_bandwidths: typing.Dict,
                      user_id: int,
                      user_name: str) -> bool:
    print(new_bandwidths, user_id, user_name)
    return False


def my_change_bandwidths(new_bandwidths: dict,
                         user_id: int,
                         user_name: str) ->bool:
    print(new_bandwidths, user_id, user_name)
    return True


def main():
    my_id, my_name = 23, "Tiras"
    simple_dict = {"Hello": "Moon"}
    change_bandwidths(simple_dict, my_id, my_name)
    new_dict = {"new": "energy source"}
    my_change_bandwidths(new_dict, my_id, my_name)

if __name__ == "__main__":
    main()

Keduanya berfungsi dengan baik, sepertinya tidak ada perbedaan.

Saya telah membaca typingdokumentasi modul .

Di antara typing.Dictatau dictmana yang harus saya gunakan dalam program ini?

joe
sumber
11
Perhatikan bahwa Python tidak benar - benar menerapkan petunjuk tipe. Mereka hanya petunjuk , mereka tidak digunakan pada waktu proses, atau bahkan waktu kompilasi, untuk memberlakukan tipe. Python mungkin diketik dengan kuat (kebalikan dari pengetikan lemah), itu juga diketik secara dinamis (kebalikan dari pengetikan ketat). Lihat Apakah Python diketik dengan kuat? . Alat eksternal seperti mypy dapat menggunakan petunjuk ini untuk membantu Anda menulis kode yang lebih baik, dalam proses yang disebut analisis statis.
Martijn Pieters
1
@MartijnPieters Saya dulu suka menggunakan petunjuk tipe dalam kode saya bersama MyPy dan berpura-pura saya bisa menggunakan Python dengan keamanan tipe. Sayangnya saya mendapat A) kode yang tidak berfungsi pada <3.4 dan B) orang menertawakan saya karena tampaknya, petunjuk tipe adalah bahan tertawaan. Sangat disayangkan.
kucing
3
@cat: Type hinting diperkenalkan ke Python oleh seorang karyawan Facebook, karena kami sangat sukses dengan menambahkan fitur yang sama ke PHP (lihat hack ). Siapa pun yang tertawa tidak pernah membangun proyek besar dengan lebih dari segelintir insinyur.
Martijn Pieters
3
@MartijnPieters Tidak, def a(b: int) -> bool:ini adalah kesalahan sintaks di Python 2.7, dan saya pikir itu adalah kesalahan sintaks di versi lama Python 3 juga.
kucing
1
@cat: Anda berbicara tentang anotasi fungsi di sini, sintaksis yang telah ditambahkan ke Python 3.0. Jadi satu-satunya versi di mana itu merupakan kesalahan sintaksis adalah 2.7, itulah mengapa mypy mendukung pemberian informasi itu dalam komentar.
Martijn Pieters

Jawaban:

147

Tidak ada perbedaan nyata antara menggunakan file biasa typing.Dictdandict , tidak.

Namun, typing.Dictadalah tipe Generik * yang memungkinkan Anda menentukan jenis kunci dan nilai juga , membuatnya lebih fleksibel:

def change_bandwidths(new_bandwidths: typing.Dict[str, str],
                      user_id: int,
                      user_name: str) -> bool:

Dengan demikian, bisa jadi di beberapa titik dalam masa proyek Anda, Anda ingin mendefinisikan argumen kamus sedikit lebih tepat, di mana perluasan typing.Dictke typing.Dict[key_type, value_type]adalah perubahan 'lebih kecil' daripada mengganti dict.

Anda dapat membuatnya lebih umum dengan menggunakan Mappingatau MutableMappingketik di sini; karena fungsi Anda tidak perlu mengubah pemetaan, saya akan tetap menggunakannya Mapping. A dictadalah satu pemetaan, tetapi Anda dapat membuat objek lain yang juga memenuhi antarmuka pemetaan, dan fungsi Anda mungkin masih berfungsi dengan itu:

def change_bandwidths(new_bandwidths: typing.Mapping[str, str],
                      user_id: int,
                      user_name: str) -> bool:

Sekarang Anda jelas mengatakan pengguna lain dari fungsi ini bahwa kode Anda tidak akan benar-benar mengubah yang new_bandwidthspemetaan berlalu di.

Implementasi Anda yang sebenarnya hanya mengharapkan objek yang dapat dicetak. Itu mungkin implementasi uji coba, tetapi seperti yang ada, kode Anda akan terus berfungsi jika Anda menggunakannya new_bandwidths: typing.Any, karena objek apa pun di Python dapat dicetak.


* : Catatan: Jika Anda menggunakan Python 3.7 atau yang lebih baru, Anda dapat menggunakan dictsebagai tipe generik jika Anda memulai modul Anda dengan from __future__ import annotations, dan mulai dari Python 3.9, dict(serta wadah standar lainnya) mendukung digunakan sebagai tipe generik bahkan tanpa itu direktif .

Martijn Pieters
sumber
2
Contoh tambahan yang berguna adalah ketika nilai kamus dapat berupa tipe yang berbeda misalnya {"name": "bob", "age" : 51}, apakah itu seperti typing.Mapping[Union[str, int]? Bagaimana dengan kamus bersarang seperti {"person": {"name":"bob", "age": 51}apakah itu seperti itu typing.Mapping[str, typing.Mapping[Union[str, int]]? Menggunakan Unionseperti itu mengganggu saya karena ini bukan skema yang ketat karena tidak ada pemesanan. Mungkin tidak apa-apa, atau apakah ada alternatif?
Davos
1
Tidak apa-apa tentang Unionpertanyaan Saya melihat itu masih diskusi terbuka github.com/python/typing/issues/28
Davos
1
Ini tampaknya sangat menarik, berguna dan terkait python.org/dev/peps/pep-0589
Greg Hilston
@GregHilston: itu sebenarnya tentang cara membatasi kunci apa yang dapat dimuat kamus, dan menentukan jenis apa yang harus dimiliki setiap nilai terkait.
Martijn Pieters
1
@GregHilston: ah, ya, benar.
Martijn Pieters
26

typing.Dictadalah versi umum dari dict:

class typing.Dict(dict, MutableMapping[KT, VT])

Versi umum dari dict. Penggunaan jenis ini adalah sebagai berikut:

def get_position_in_index(word_list: Dict[str, int], word: str) -> int:
     return word_list[word]

Di sini Anda dapat menentukan jenis kunci dan nilai di dict: Dict[str, int]

AKS
sumber