Lingkup dalam Python 'untuk' loop

177

Saya tidak bertanya tentang aturan pelingkupan Python; Saya mengerti secara umum bagaimana pelingkupan bekerja di Python untuk loop. Pertanyaan saya adalah mengapa keputusan desain dibuat dengan cara ini. Misalnya (tidak ada permainan kata-kata):

for foo in xrange(10):
    bar = 2
print(foo, bar)

Di atas akan dicetak (9,2).

Ini menurut saya aneh: 'foo' benar-benar hanya mengendalikan loop, dan 'bar' didefinisikan di dalam loop. Saya bisa mengerti mengapa mungkin perlu 'bar' untuk dapat diakses di luar loop (jika tidak, untuk loop akan memiliki fungsi yang sangat terbatas). Apa yang saya tidak mengerti adalah mengapa perlu untuk variabel kontrol untuk tetap berada dalam ruang lingkup setelah loop keluar. Dalam pengalaman saya, ini hanya mengacaukan namespace global dan membuatnya lebih sulit untuk melacak kesalahan yang akan ditangkap oleh penerjemah dalam bahasa lain.

chimeracoder
sumber
6
Jika Anda tidak ingin forloop mengacaukan namespace global Anda, bungkuslah dalam suatu fungsi. Closures berlimpah!
jathanism
24
Kecuali Anda menjalankan loop di namespace global (tidak umum), itu mengacaukan namespace lokal .
Glenn Maynard
3
Jika ini tidak ada, bagaimana Anda akan melanjutkan pemrosesan nanti pada titik yang Anda tinggalkan di dalam loop? Cukup tentukan variabel kontrol sebelum loop?
endolith
9
@endolith Ya ... Mengapa tidak mengharuskan itu?
Steven Lu
3
orang baik hanya akan lebih suka apa yang mereka lakukan. Saya akan mengatakan hal semacam ini menyakiti pembuat kode python yang terbiasa dengan hal semacam ini dan harus melalui proses yang menyakitkan ketika beralih ke bahasa yang berbeda. Bagi kita semua, itu jalan pintas kecil yang rapi kurasa.
Steven Lu

Jawaban:

107

Jawaban yang paling mungkin adalah bahwa hal itu hanya membuat tata bahasa tetap sederhana, belum menjadi batu sandungan untuk adopsi, dan banyak yang senang karena tidak harus mengacaukan ruang lingkup di mana nama tersebut dimiliki ketika menetapkannya dalam konstruksi lingkaran. Variabel tidak dideklarasikan dalam lingkup, itu tersirat oleh lokasi pernyataan tugas. Kata globalkunci ada hanya karena alasan ini (untuk menandakan bahwa penugasan dilakukan pada lingkup global).

Memperbarui

Inilah diskusi yang bagus tentang topik ini: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

Usulan sebelumnya untuk membuat variabel for-loop lokal ke loop telah tersandung pada masalah kode yang ada yang bergantung pada variabel loop mempertahankan nilainya setelah keluar dari loop, dan tampaknya ini dianggap sebagai fitur yang diinginkan.

Singkatnya, Anda mungkin bisa menyalahkannya di komunitas Python: P

Jeremy Brown
sumber
2
Bagaimana tata bahasa akan lebih rumit jika ruang lingkup variabel induksi terbatas pada badan loop? Perubahan seperti itu akan terbatas pada analisis semantik dengan Python, bukan pada tata bahasanya.
Charles
6
Loop bukan blok dalam Python. Perubahan perilaku semacam ini membutuhkan perubahan tata bahasa secara mendasar atau menyediakan kasus khusus. Seluruh konsep variabel induksi juga tidak dinyatakan dalam tata bahasa saat ini. Tata bahasa menyediakan kontrak untuk bagaimana penafsir akan menafsirkan. Maksud saya adalah bahwa saya tidak dapat melihat bagaimana perubahan perilaku ini dapat dilakukan tanpa membuat tata bahasa lebih rumit. Semuanya diperdebatkan karena efek samping dari keputusan desain telah menjadi fitur.
Jeremy Brown
1
Posting ini di sini mail.python.org/pipermail/python-dev/2005-September/056677.html memberikan rincian lebih lanjut tentang kecepatan dan komplikasi yang disinggung oleh Mr. Brown.
rajesh
62

Python tidak memiliki blok, seperti halnya beberapa bahasa lain (seperti C / C ++ atau Java). Oleh karena itu, unit pelingkupan dalam Python adalah suatu fungsi.

atzz
sumber
3
Saya bingung - apa yang mencegah Python melakukan scoping untuk loop dengan cara yang sama dengan fungsi scoping?
chimeracoder
36
Tidak sepenuhnya benar, hanya saja tata bahasanya tidak menjadi gila. ( docs.python.org/reference/… ) "Blok adalah bagian dari teks program Python yang dieksekusi sebagai satu unit. Berikut ini adalah blok: modul, badan fungsi, dan definisi kelas ..."
Jeremy Brown
1
@tangan kembali, tidak ada. Itu hanya dianggap tidak perlu.
habnabit
@ Jeremy Brown - memang. Catatan yang bagus.
atzz
6
@thebackhand - dalam bahasa dengan blok, ruang lingkup foradalah perpanjangan alami dari prinsip umum. Dalam Python itu harus menjadi kasus khusus, dan kasus-kasus khusus harus dihindari kecuali mereka memiliki manfaat menarik.
atzz
39

Kasus yang sangat berguna untuk ini adalah ketika menggunakan enumeratedan Anda ingin jumlah total pada akhirnya:

for count, x in enumerate(someiterator, start=1):
    dosomething(count, x)
print "I did something {0} times".format(count)

Apakah ini perlu? Tidak. Tapi, itu pasti nyaman.

Hal lain yang perlu diperhatikan: di Python 2, variabel dalam daftar pemahaman bocor juga:

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

Tapi, hal yang sama tidak berlaku untuk Python 3.

carl
sumber
4
Anda bisa melakukan itu mungkin dalam elseklausa, yaitu. else: print "I did something {0} times".format(count)- sebelum lingkup lokal (yang tidak ada dalam Python) menghilang
Nas Banov
3
Hanya contoh kedua tidak bekerja di Python 3, kan? Yang pertama masih? Catatan mengapa dihapus dari Python 3?
endolith
7
untuk penghitungan, item dalam penghitungan (a, mulai = 1): # indeks default dari nol
Tao Zhang
3
Contoh pertama, alih-alih menjadi kasus penggunaan yang baik, tampaknya lebih seperti bukti bahwa aturan pelingkupan ini berbahaya dan tidak boleh diandalkan. Bagaimana jika someiteratorkosong?
maks
1
@Nas Meskipun elseklausa dapat digunakan dalam kasus ini, itu tidak akan berfungsi secara umum karena badan loop bisa breakprematur.
jamesdlin
2

Jika Anda memiliki pernyataan break di loop (dan ingin menggunakan nilai iterasi nanti, mungkin untuk mengambil kembali, mengindeks sesuatu, atau memberikan status), itu akan menghemat satu baris kode dan satu tugas, jadi ada kemudahan.

Mac
sumber
1

Salah satu pengaruh utama Python adalah ABC , bahasa yang dikembangkan di Belanda untuk mengajarkan konsep pemrograman kepada pemula. Pencipta Python, Guido van Rossum, bekerja di ABC selama beberapa tahun pada 1980-an. Saya hampir tidak tahu apa-apa tentang ABC, tetapi karena ini ditujukan untuk pemula, saya kira itu harus memiliki cakupan yang terbatas, seperti BASIC awal.

baik hati
sumber
-1

Sebagai permulaan, jika variabel lokal untuk loop, loop tersebut tidak akan berguna untuk kebanyakan pemrograman dunia nyata.

Dalam situasi saat ini:

# Sum the values 0..9
total = 0
for foo in xrange(10):
    total = total + foo
print total

hasil panen 45. Sekarang, pertimbangkan bagaimana tugas bekerja di Python. Jika variabel loop benar-benar lokal:

# Sum the values 0..9?
total = 0
for foo in xrange(10):
    # Create a new integer object with value "total + foo" and bind it to a new
    # loop-local variable named "total".
    total = total + foo
print total

menghasilkan 0, karena totaldi dalam loop setelah penugasan tidak variabel yang sama seperti di totalluar loop. Ini tidak akan menjadi perilaku yang optimal atau yang diharapkan.

Kirk Strauser
sumber
5
Tidak menjawab pertanyaan. OP bertanya tentang foo, bukan total (atau bilah dalam contoh mereka).
James Bradbury
6
@ JamesBradbury totaldan foomasih memiliki ikatan local-loop dalam skenario OP dan logikanya sama.
Kirk Strauser
2
OP: "Saya bisa mengerti mengapa mungkin 'bar' harus dapat diakses di luar loop (jika tidak, untuk loop akan memiliki fungsi yang sangat terbatas). Apa yang saya tidak mengerti adalah mengapa variabel kontrol diperlukan untuk tetap dalam lingkup setelah loop keluar. " (penekanan milikku)
James Bradbury
2
@ JamesBradbury Anda mungkin benar, tapi saya menjawab ini tiga tahun lalu dan mungkin tidak layak untuk diperdebatkan sekarang.
Kirk Strauser