Apa sebenarnya aturan pelingkupan Python?
Jika saya memiliki beberapa kode:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
Dimana x
ditemukan? Beberapa pilihan yang mungkin termasuk daftar di bawah ini:
- Dalam file sumber terlampir
- Di namespace kelas
- Dalam definisi fungsi
- Dalam variabel untuk loop indeks
- Di dalam for loop
Juga ada konteks selama eksekusi, ketika fungsi spam
dilewatkan di tempat lain. Dan mungkin fungsi lambda melewati sedikit berbeda?
Harus ada referensi atau algoritma sederhana di suatu tempat. Ini adalah dunia yang membingungkan bagi programmer Python perantara.
python
scope
dynamic-languages
Charles Merriam
sumber
sumber
Jawaban:
Sebenarnya, aturan ringkas untuk resolusi Python Scope, dari Learning Python, 3rd. Ed. . (Aturan ini khusus untuk nama variabel, bukan atribut. Jika Anda mereferensikan tanpa titik, aturan ini berlaku.)
Aturan LEGB
L ocal - Nama yang ditetapkan dengan cara apa pun dalam suatu fungsi (
def
ataulambda
), dan tidak dinyatakan global dalam fungsi ituE -fungsi penutup - Nama yang ditetapkan dalam lingkup lokal dari setiap dan semua fungsi penutup statis (
def
ataulambda
), dari dalam ke luarG lobal (module) - Nama yang ditetapkan di tingkat atas file modul, atau dengan menjalankan
global
pernyataan didef
dalam fileB uilt-in (Python) - Nama preassigned di built-in modul nama:
open
,range
,SyntaxError
, dllJadi, dalam kasus
The
for
Loop tidak memiliki ruang nama sendiri. Dalam urutan LEGB, cakupannya adalahdef spam
(dicode3
,code4
, dancode5
)def
)x
dinyatakan secara global dalam modul (dalamcode1
)?x
dengan Python.x
tidak akan pernah ditemukan dicode2
(bahkan dalam kasus di mana Anda mungkin mengharapkannya, lihat jawaban Antti atau di sini ).sumber
global(var_name)
secara sintaksis salah. Sintaks yang benar adalahglobal var_name
tanpa tanda kurung. Anda memiliki poin yang valid.>>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3
y
- masing sedang ditulis dan tidak adaglobal y
deklarasi - lihat komentar @ Peter.Pada dasarnya, satu-satunya hal di Python yang memperkenalkan ruang lingkup baru adalah definisi fungsi. Kelas adalah sedikit kasus khusus di mana segala sesuatu yang didefinisikan langsung di tubuh ditempatkan di namespace kelas, tetapi mereka tidak dapat diakses secara langsung dari dalam metode (atau kelas bersarang) yang dikandungnya.
Dalam contoh Anda, hanya ada 3 cakupan di mana x akan dicari:
ruang lingkup spam - berisi semua yang didefinisikan dalam code3 dan code5 (serta code4, variabel loop Anda)
Cakupan global - berisi semua yang didefinisikan dalam kode1, serta Foo (dan perubahan apa pun setelahnya)
Namespace builtin. Sedikit kasus khusus - ini berisi berbagai fungsi dan tipe Python builtin seperti len () dan str (). Biasanya ini tidak boleh dimodifikasi oleh kode pengguna apa pun, jadi harap ini berisi fungsi standar dan tidak ada yang lain.
Lebih banyak cakupan hanya muncul ketika Anda memperkenalkan fungsi bersarang (atau lambda) ke dalam gambar. Ini akan berperilaku cukup seperti yang Anda harapkan. Fungsi bersarang dapat mengakses segala sesuatu dalam lingkup lokal, serta apa pun dalam lingkup fungsi terlampir. misalnya.
Pembatasan:
Variabel dalam lingkup selain variabel fungsi lokal dapat diakses, tetapi tidak dapat dikembalikan ke parameter baru tanpa sintaksis lebih lanjut. Sebagai gantinya, penugasan akan membuat variabel lokal baru alih-alih memengaruhi variabel dalam lingkup induk. Sebagai contoh:
Untuk benar-benar memodifikasi ikatan variabel global dari dalam lingkup fungsi, Anda perlu menentukan bahwa variabel tersebut bersifat global dengan kata kunci global. Misalnya:
Saat ini tidak ada cara untuk melakukan hal yang sama untuk variabel dalam melampirkan lingkup fungsi , tetapi Python 3 memperkenalkan kata kunci baru, "
nonlocal
" yang akan bertindak dalam cara yang mirip dengan global, tetapi untuk lingkup fungsi bersarang.sumber
Tidak ada jawaban menyeluruh tentang waktu Python3, jadi saya membuat jawaban di sini. Sebagian besar yang dijelaskan di sini dirinci dalam Resolusi 4.2.2 nama - nama dokumentasi Python 3.
Seperti yang diberikan dalam jawaban lain, ada 4 cakupan dasar, LEGB, untuk Lokal, Melampirkan, Global dan Builtin. Selain itu, ada ruang lingkup khusus, badan kelas , yang tidak mencakup ruang lingkup terlampir untuk metode yang didefinisikan dalam kelas; tugas apa pun dalam tubuh kelas membuat variabel dari sana terikat di tubuh kelas.
Terutama, tidak ada pernyataan blokir, selain
def
danclass
, membuat ruang lingkup variabel. Dalam Python 2 daftar pemahaman tidak membuat lingkup variabel, namun dalam Python 3 variabel lingkaran dalam daftar daftar dibuat dalam lingkup baru.Untuk menunjukkan kekhasan badan kelas
Jadi tidak seperti dalam fungsi body, Anda dapat menetapkan kembali variabel ke nama yang sama di kelas tubuh, untuk mendapatkan variabel kelas dengan nama yang sama; pencarian lebih lanjut pada nama ini diselesaikan ke variabel kelas sebagai gantinya.
Salah satu kejutan yang lebih besar bagi banyak pendatang baru di Python adalah
for
loop tidak membuat lingkup variabel. Dalam Python 2, daftar pemahaman tidak membuat ruang lingkup baik (sementara generator dan pemahaman dikte lakukan!) Alih-alih mereka membocorkan nilai dalam fungsi atau lingkup global:Pemahaman dapat digunakan sebagai cara yang licik (atau mengerikan jika Anda mau) untuk membuat variabel yang dapat dimodifikasi dalam ekspresi lambda di Python 2 - ekspresi lambda memang menciptakan ruang lingkup variabel, seperti
def
pernyataan itu, tetapi dalam lambda tidak ada pernyataan yang diizinkan. Penugasan sebagai pernyataan dalam Python berarti bahwa tidak ada penugasan variabel dalam lambda yang diizinkan, tetapi pemahaman daftar adalah ekspresi ...Perilaku ini telah diperbaiki dalam Python 3 - tidak ada ekspresi pemahaman atau variabel generator bocor.
Global benar-benar berarti ruang lingkup modul; modul python utama adalah
__main__
; semua modul yang diimpor dapat diakses melaluisys.modules
variabel; untuk mendapatkan akses ke__main__
satu dapat menggunakansys.modules['__main__']
, atauimport __main__
; sangat dapat diterima untuk mengakses dan menetapkan atribut di sana; mereka akan ditampilkan sebagai variabel dalam lingkup global modul utama.Jika suatu nama pernah ditugaskan ke dalam lingkup saat ini (kecuali dalam lingkup kelas), itu akan dianggap milik lingkup itu, jika tidak maka akan dianggap milik setiap lingkup terlampir yang ditugaskan ke variabel (itu mungkin tidak ditugaskan belum, atau tidak sama sekali), atau akhirnya ruang lingkup global. Jika variabel dianggap lokal, tetapi belum disetel, atau telah dihapus, membaca nilai variabel akan menghasilkan
UnboundLocalError
, yang merupakan subkelas dariNameError
.Lingkup dapat menyatakan bahwa ia secara eksplisit ingin memodifikasi variabel global (cakupan modul), dengan kata kunci global:
Ini juga dimungkinkan bahkan jika dibayangi dalam cakupan terlampir:
Dalam python 2 tidak ada cara mudah untuk mengubah nilai dalam lingkup terlampir; biasanya ini disimulasikan dengan memiliki nilai yang bisa berubah, seperti daftar dengan panjang 1:
Namun dalam python 3,
nonlocal
datang untuk menyelamatkan:The
nonlocal
dokumentasi mengatakan bahwayaitu
nonlocal
selalu mengacu pada ruang lingkup non-global terluar terdalam di mana nama telah diikat (yaitu ditugaskan untuk, termasuk digunakan sebagaifor
variabel target, dalamwith
klausa, atau sebagai parameter fungsi).Setiap variabel yang tidak dianggap lokal ke lingkup saat ini, atau ruang lingkup apa pun, adalah variabel global. Nama global dilihat dalam kamus global modul; jika tidak ditemukan, global kemudian dilihat dari modul builtins; nama modul diubah dari python 2 menjadi python 3; di python 2 dulu
__builtin__
dan di python 3 sekarang disebutbuiltins
. Jika Anda menetapkan atribut modul builtin, modul tersebut akan terlihat setelahnya ke modul apa pun sebagai variabel global yang dapat dibaca, kecuali modul itu membayangi mereka dengan variabel globalnya sendiri dengan nama yang sama.Membaca modul builtin juga bisa bermanfaat; misalkan Anda menginginkan fungsi cetak gaya python 3 di beberapa bagian file, tetapi bagian lain dari file masih menggunakan
print
pernyataan. Di Python 2.6-2.7 Anda bisa mendapatkanprint
fungsi Python 3 dengan:The
from __future__ import print_function
sebenarnya tidak mengimporprint
fungsi di mana saja di Python 2 - bukan hanya menonaktifkan aturan parsing untukprint
pernyataan dalam modul saat ini, penangananprint
seperti variabel pengenal lainnya, dan dengan demikian memungkinkanprint
fungsi mendongak di builtin.sumber
Aturan pelingkupan untuk Python 2.x telah diuraikan di jawaban lain. Satu-satunya hal yang akan saya tambahkan adalah bahwa dalam Python 3.0, ada juga konsep lingkup non-lokal (ditunjukkan oleh kata kunci 'nonlokal'). Hal ini memungkinkan Anda untuk mengakses lingkup luar secara langsung, dan membuka kemampuan untuk melakukan beberapa trik yang rapi, termasuk penutupan leksikal (tanpa peretasan jelek yang melibatkan objek yang dapat diubah).
EDIT: Inilah PEP dengan informasi lebih lanjut tentang ini.
sumber
Contoh cakupan yang sedikit lebih lengkap:
keluaran:
sumber
method
danmethod_local_ref
harus disorot.method
dapat mengakses variabel global dan mencetaknya seperti pada5. Global x
. Tetapimethod_local_ref
tidak bisa karena nanti mendefinisikan variabel lokal dengan nama yang sama. Anda dapat menguji ini dengan menghapusx = 200
garis dan melihat perbedaannyaPython menyelesaikan variabel Anda dengan - umumnya - tiga ruang nama yang tersedia.
Ada dua fungsi:
globals
danlocals
yang menunjukkan Anda isi dua ruang nama ini.Ruang nama dibuat oleh paket, modul, kelas, konstruksi objek, dan fungsi. Tidak ada rasa ruang nama lain.
Dalam hal ini, panggilan ke fungsi yang dinamai
x
harus diselesaikan dalam ruang nama lokal atau ruang nama global.Lokal dalam hal ini, adalah fungsi tubuh metode
Foo.spam
.Global - baik - global.
Aturannya adalah untuk mencari ruang lokal bersarang yang dibuat oleh fungsi metode (dan definisi fungsi bersarang), lalu cari global. Itu dia.
Tidak ada ruang lingkup lain. The
for
pernyataan (dan pernyataan majemuk lain sepertiif
dantry
) tidak menciptakan lingkup bersarang baru. Hanya definisi (paket, modul, fungsi, kelas, dan instance objek.)Di dalam definisi kelas, nama-nama adalah bagian dari namespace kelas.
code2
, misalnya, harus memenuhi syarat dengan nama kelas. UmumnyaFoo.code2
. Namun,self.code2
juga akan berfungsi karena objek Python melihat kelas yang berisi sebagai back-back.Objek (turunan dari sebuah kelas) memiliki variabel turunan. Nama-nama ini berada di namespace objek. Mereka harus memenuhi syarat oleh objek. (
variable.instance
.)Dari dalam metode kelas, Anda memiliki penduduk lokal dan global. Anda mengatakan
self.variable
untuk memilih contoh sebagai namespace. Anda akan mencatat bahwaself
ini adalah argumen untuk setiap fungsi anggota kelas, menjadikannya bagian dari namespace lokal.Lihat Python Aturan Lingkup , Python Lingkup , Ruang Lingkup Variabel .
sumber
Python has two namespaces available. Global and local-to-something.
x tidak ditemukan karena Anda belum mendefinisikannya. :-) Ini bisa ditemukan di code1 (global) atau code3 (lokal) jika Anda meletakkannya di sana.
code2 (anggota kelas) tidak terlihat oleh kode di dalam metode dari kelas yang sama - Anda biasanya akan mengaksesnya menggunakan sendiri. code4 / code5 (loop) hidup dalam lingkup yang sama dengan code3, jadi jika Anda menulis ke x di sana Anda akan mengubah instance x yang didefinisikan dalam code3, bukan membuat x baru.
Python memiliki cakupan yang statis, jadi jika Anda meneruskan 'spam' ke fungsi lain, spam masih akan memiliki akses ke global dalam modul asalnya (didefinisikan dalam kode1), dan cakupan lain yang berisi (lihat di bawah). anggota kode2 akan diakses lagi melalui self.
lambda tidak berbeda dengan def. Jika Anda memiliki lambda yang digunakan di dalam suatu fungsi, itu sama dengan mendefinisikan fungsi bersarang. Dalam Python 2.2 dan seterusnya, cakupan bersarang tersedia. Dalam hal ini, Anda dapat mengikat x pada level fungsi apa saja dan Python akan mengambil instance paling dalam:
fun3 melihat instance x dari lingkup berisi terdekat, yang merupakan lingkup fungsi yang terkait dengan fun2. Tetapi x instance lainnya, yang didefinisikan dalam fun1 dan global, tidak terpengaruh.
Sebelum nested_scopes - dengan Python pre-2.1, dan 2.1 kecuali Anda secara khusus meminta fitur menggunakan impor dari masa depan - cakupan fun1 dan fun2 tidak terlihat fun3, jadi jawaban S.Lott berlaku dan Anda akan mendapatkan global x :
sumber
Dengan Python,
Jika variabel tidak dapat ditemukan dalam lingkup saat ini, silakan merujuk ke urutan LEGB.
sumber