Apa yang dilakukan perilaku usus besar yang aneh ini?

104

Saya menggunakan Python 3.6.1, dan saya menemukan sesuatu yang sangat aneh. Saya mengalami kesalahan ketik tugas kamus sederhana yang membutuhkan waktu lama untuk menemukannya.

context = {}
context["a"]: 2
print(context)

Keluaran

{}

Apa yang context["a"]: 2dilakukan kode itu ? Itu tidak menaikkan SyntaxErrorkapan harus IMO. Awalnya saya pikir itu membuat sepotong. Namun, pengetikan repr(context["a"]: 2)menimbulkan a SyntaxError. Saya juga mengetik context["a"]: 2di konsol dan konsol tidak mencetak apa pun. Saya pikir mungkin itu kembali None, tetapi saya tidak begitu yakin.

Saya juga berpikir itu bisa menjadi satu baris pernyataan if, tetapi itu juga seharusnya tidak menjadi sintaks yang tepat.

Selain itu, context["a"]harus menaikkan a KeyError.

Saya bingung Apa yang sedang terjadi?

justengel
sumber
2
Pertanyaan ini sudah memiliki dupe dan cukup jelas ini membingungkan bagi pemula Python. Saya rasa ini adalah yang terburuk jika Python adalah satu-satunya bahasa Anda, di mana petunjuk tipe dan definisi variabel sebelum inisialisasi secara umum mungkin terasa asing. Saya membayangkan meningkatkan kesalahan tidak mungkin karena perilaku ini disengaja dan terkadang berguna seperti yang dijelaskan dalam PEP 526, dan Anda tidak ingin merusak kompatibilitas. Namun, saya ingin tahu apakah pengembang Python akan mempertimbangkan untuk menambahkan pesan peringatan yang berguna untuk beberapa kasus.
Chris_Rands
1
Apakah ini menjawab pertanyaan Anda? Apa itu anotasi variabel di Python 3.6?
Georgy

Jawaban:

98

Anda tidak sengaja menulis anotasi variabel yang benar secara sintaksis . Fitur itu diperkenalkan di Python 3.6 (lihat PEP 526 ).

Meskipun anotasi variabel diurai sebagai bagian dari tugas yang dianotasi , pernyataan tugas bersifat opsional :

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

Jadi, dalam context["a"]: 2

  • context["a"] adalah target anotasi
  • 2 adalah anotasi itu sendiri
  • context["a"] dibiarkan tidak dimulai

PEP menyatakan bahwa "target anotasi dapat berupa target penugasan tunggal yang valid, setidaknya secara sintaksis (terserah pemeriksa jenis apa yang harus dilakukan dengan ini)" , yang berarti bahwa kunci tidak perlu ada untuk menjadi beranotasi (karenanya tidak KeyError). Berikut contoh dari PEP asli:

d = {}
d['a']: int = 0  # Annotates d['a'] with int.
d['b']: int      # Annotates d['b'] with int.

Biasanya, ekspresi anotasi harus dievaluasi ke jenis Python - setelah semua penggunaan utama anotasi adalah petunjuk jenis, tetapi tidak diberlakukan. Anotasi dapat berupa ekspresi Python apa pun yang valid , apa pun jenis atau nilai hasilnya.

Seperti yang Anda lihat, saat ini petunjuk tipe sangat permisif dan jarang berguna, kecuali Anda memiliki pemeriksa tipe statis seperti mypy .

vaultah
sumber
12
Bukankah seharusnya ini membutuhkan =operator penugasan? Kuncinya tidak ada. Ini terasa salah bagiku.
justengel
1
Dalam hal ini, : adalah operator penugasan. Kami hanya "menetapkan" anotasi jenis saja, bukan kunci. Saya ragu ada alasan untuk mengizinkannya, hanya efek samping yang tidak disengaja dari penambahan sintaks anotasi.
chepner
1
@chepner Sepertinya ini bukan efek samping imho. Inilah yang dirancang untuk dilakukan oleh PEP terkait.
Ma0
6
Aneh bahwa ini memungkinkan Anda untuk membuat anotasi target yang belum ditentukan. Jika baris pertama saya adalah x: strdan segera diikuti oleh type(x), penerjemah akan memunculkan a NameError. IMO sintaks harus menegakkan objek yang telah ditentukan sebelumnya, atau ditentukan di tempat. Ini hanya menimbulkan kebingungan.
r.ook
2
@Idlehands Ini menggagalkan tujuannya. Memiliki x = 'i am a string'prior untuk x: strmembuat jenis yang terakhir menjadi mubazir .. Ini seharusnya tidak ditambahkan sama sekali. Itu bagus sebagai komentar; Saya tidak pernah menunjukkannya digunakan dengan satu atau lain cara.
Ma0