Python sedikit aneh karena menyimpan semuanya dalam kamus untuk berbagai cakupan. Aslinya a, b, c berada dalam ruang lingkup teratas dan dalam kamus paling atas itu. Fungsi memiliki kamus sendiri. Saat Anda mencapai print(a)
dan print(b)
pernyataan, tidak ada yang namanya dalam kamus, jadi Python mencari daftar dan menemukan mereka di kamus global.
Sekarang kita bisa c+=1
, yang, tentu saja, setara dengan c=c+1
. Ketika Python memindai baris itu, dikatakan "aha, ada variabel bernama c, saya akan memasukkannya ke dalam kamus lingkup lokal saya." Kemudian ketika ia pergi mencari nilai untuk c untuk c di sisi kanan penugasan, ia menemukan variabel lokal bernama c , yang belum memiliki nilai, dan melempar kesalahan.
Pernyataan yang global c
disebutkan di atas hanya memberitahu parser bahwa ia menggunakan c
dari lingkup global sehingga tidak perlu yang baru.
Alasannya mengatakan ada masalah pada baris yang dilakukannya adalah karena secara efektif mencari nama-nama sebelum mencoba untuk menghasilkan kode, dan dalam beberapa hal tidak berpikir itu benar-benar melakukan garis itu. Saya berpendapat bahwa ini adalah bug kegunaan, tetapi umumnya merupakan praktik yang baik untuk hanya belajar untuk tidak menganggap pesan kompiler terlalu serius.
Jika itu suatu kenyamanan, saya mungkin menghabiskan sehari menggali dan bereksperimen dengan masalah yang sama ini sebelum saya menemukan sesuatu yang ditulis Guido tentang kamus yang Menjelaskan Segalanya.
Perbarui, lihat komentar:
Itu tidak memindai kode dua kali, tetapi memindai kode dalam dua fase, lexing dan parsing.
Pertimbangkan bagaimana penguraian baris kode ini bekerja. Lexer membaca teks sumber dan memecahnya menjadi leksem, "komponen terkecil" dari tata bahasa. Jadi ketika itu menyentuh garis
c+=1
itu memecahnya menjadi sesuatu seperti
SYMBOL(c) OPERATOR(+=) DIGIT(1)
Pengurai akhirnya ingin menjadikan ini menjadi pohon parse dan menjalankannya, tetapi karena ini adalah tugas, sebelum itu, ia mencari nama c dalam kamus lokal, tidak melihatnya, dan memasukkannya ke dalam kamus, menandai sebagai tidak diinisialisasi. Dalam bahasa yang dikompilasi penuh, itu hanya akan pergi ke tabel simbol dan menunggu parse, tetapi karena TIDAK AKAN memiliki kemewahan pass kedua, lexer melakukan sedikit pekerjaan ekstra untuk membuat hidup lebih mudah di kemudian hari. Hanya saja, kemudian ia melihat OPERATOR, melihat bahwa aturan mengatakan "jika Anda memiliki operator + = sisi kiri pasti telah diinisialisasi" dan mengatakan "whoops!"
Intinya di sini adalah bahwa itu belum benar-benar memulai parse dari garis . Ini semua terjadi semacam persiapan untuk parse yang sebenarnya, sehingga penghitung baris belum maju ke baris berikutnya. Jadi ketika sinyal kesalahan, ia masih berpikir itu pada baris sebelumnya.
Seperti yang saya katakan, Anda bisa berpendapat itu adalah bug kegunaan, tetapi sebenarnya hal yang cukup umum. Beberapa kompiler lebih jujur tentang hal itu dan mengatakan "kesalahan pada atau di sekitar jalur XXX", tetapi yang ini tidak.