x = 3
y = [3]
def test1():
x += 1
print x
def test2():
y[0] = 4
y.append(5)
print y
test2()
test1()
这段代码执行结果: test2()成功打印[4, 5], test1()却报错: UnboundLocalError: local variable 'x' referenced before assignment
想不明白,为什么会这样,全局变量在函数里可以直接打印,但是如果要改变它的值,会报错,但是test2()为什么不报错?如果把y换成dict类型,就能在函数里不需要用global声明,可以直接改变y的值,但如果是str或number,就会报错,为什么?
Malah, soalan ini boleh diketepikan sama ada objek yang dirujuk oleh pembolehubah itu boleh berubah atau tidak berubah Apa yang perlu kita perhatikan ialah kedudukan pembolehubah, titik masa dan skop. definisi.
Pertimbangkan kod berikut:
Kod ini akan menimbulkan ralat:
a
ialah pembolehubah param fungsitest
, jadi ia tergolong dalam pembolehubah tempatan, dan skopnya ialah fungsitest
Kami luluskan 1 dalam untuk dirujuk, jadi tiada masalah besar denganprint(a)
.Tetapi
b
tidak ditakrifkan dari awal hingga akhir Walaupun anda mencari mengikut prinsip LEGB, anda tidak dapat menemuinya, jadi anda menaikkanNameError
.Untuk menyelesaikan masalah ini, mungkin kita boleh menentukan pembolehubah global:
Bagus, kali ini nampaknya tiada masalah, kerana Python menemui
b
dalam skop global Sebab Python menggunakan globalb
adalah kerana kami tidak mentakrifkanb
dalam bahasa tempatan.Kemudian kita mula menetapkan pembolehubah dalam fungsi:
Keputusan:
Dua
print
dalam fungsi mencetak 1 dan 20 tidak menghairankan, tetapi mengapa nilaib
dicetak selepas meninggalkan fungsi menjadi 100?Kerana kami menulis ini dalam fungsi A tugasan juga merupakan definisi
b = 20
, jaditest
yang dilihat dalamb
semuanya tempatan, bukan global, jadi sebarang perubahan yang kami buat kepadab
Tiada perubahan akan menjejaskan globalb
.Ini memberitahu kami:
Maka bagaimana kita boleh mengendalikan pembolehubah global dalam fungsi ini memerlukan bantuan kata kunci
global
:Dengan kata kunci
global
yang menerangkanb
, Python akan menganggaptest
dalamb
sebagai pembolehubah untuk mengakses globalb
danb = 20
hanya akan dianggap sebagai Tindakan tugasan tidak mentakrifkan pembolehubah tempatan baharu.Mari kita lihat contoh yang lebih mengelirukan:
Keputusan:
muncul di sini
UnboundLocalError
, mengapa ini berlaku Sebabnya sangat mudah,b
mempunyai tindakan tugasan dan definisi dalam fungsi ini:b = 20
, jaditest
di dalamb
adalah setempat (global tidak digunakan di sini untuk menunjukkan bahawab
adalah global), jadi apabilaprint(b)
digunakan, Python akan cuba merebut tempatanb
bukannya globalb
, tetapi tragedinya ialah di sini Pada langkah pertama, tempatanb
belum ditugaskan, jadi dikatakanlocal variable 'b' referenced before assignment
dirujuk sebelum ditugaskan, yang secara semula jadi tidak mungkin.Lihat kembali contoh yang anda berikan:
Di sini, takrifan
test1
berlaku dalamx
(tiada global, danx
muncul di sebelah kiri tanda sama dengan itu, apabila merujuk kepadax
, anda pasti mahu gunakan tempatan, tetapi Kerana:Jadi apabila anda ingin mendapatkan nilai yang dirujuk oleh
x
di sebelah kanan tanda sama, anda mendapati ia belum diberikan nilai lagi, maka ini adalah sama seperti contoh di atas:Bagi
test2
anda tidak akan ada masalah:adalah kerana y tidak muncul di sebelah kiri tanda sama dalam
Kesimpulantest2
, jadi Python secara automatik menganggap bahawa globaly
digunakan, jadi sudah tentu tiada masalah!global
untuk menunjukkan keseluruhan domain, jika tidak, kaedah penulisan ini tidak sepatutnya muncul (operasi di tempat atau tugasan kemudian)
global
(Python3), tetapi itu cerita lain.
nonlocal
Soalan yang saya jawab: Python-QA
Skop pembolehubah Python ditetapkan dengan cara ini dalam ujian1, anda boleh
print x
tetapi tidak boleh mengubah suai xSesetengah orang mengatakan bahawa "pembolehubah global dalam skop tempatan harus dibaca sahaja", tetapi ini tidak benar untuk. pembolehubah rujukan keadaan ini. . .
Tempat dalam ular sawa ini sungguh mengelirukan
Ringkasnya, pengikatan pembolehubah global tidak boleh ditukar dalam skop setempat, dan alamat pembolehubah tidak boleh ditukar dalam
CPython
.Lihat: Kesilapan Biasa 4 dalam: Sepuluh Kesilapan Paling Biasa Yang Dilakukan Pengaturcara Python: Salah Faham Penghuraian Nama Pembolehubah dalam Python
Fungsi
Dalam fungsitest1
anda mempunyai operasi penugasanx += 1
, yang dianggap oleh penterjemah Python sebagai pembolehubah dalam skop tempatan fungsi Walau bagaimanapun, pembolehubahx
tidak ditakrifkan sebelum tugasan, danx
ialahnumber
, tergolong dalam jenis tidak berubah Untuk menetapkan nilai baharu kepada jenis tidak berubah, anda perlu mencipta semula objek jenis tidak berubah dan menunjuk semula pembolehubah asal ke objek yang baru dibuat, tetapi ini. objek yang baru dicipta tidak termasuk dalamLEGB
Tidak ditemui, jadi ralat akan dilaporkan
Semua operasi tugasan dalamtest2
,y
ialahlist
, yang merupakan jenis pembolehubah Senarai masih menunjuk ke alamat memori yang sama selepas lampiran kerana senarai adalah jenis pembolehubah dan boleh diubah suai , ia tidak Laporkan ralatPython
pada asasnya dibahagikan kepada tiga langkah berikut (mengambila = 3
sebagai contoh):Buat objek untuk mewakili nilai
3
Buat pembolehubah
a
, jika ia belum dibuat lagiSambungkan pembolehubah
a
ke objek baharu3
Mari kita perhatikan perubahan alamat memori pembolehubah
test2
semasa pelaksanaan fungsiy
andaOutput
Anda dapat melihat bahawa
y
sebenarnya diubah suai di tempatnya, jadi tidak perlu membuat pembolehubah berulang kali dan untukx
jenis tidak berubah, untuk memberikan nilai kepadanya, anda mesti mencipta objek baharu dahulu, walaupun nama Sama, anda dapat melihat bahawa jika tugasan berbeza dibuat setiap kali, alamat memorix
sebenarnya berbeza, yang juga boleh menjelaskan mengapastr
ataunumber
akan melaporkan ralat