Lewati ke konten utama

Penjelasan Cakupan Variabel Python dan Aturan LEGB

Pelajari seluk-beluk cakupan variabel dan kenali aturan 'LEGB'. Anda juga akan melihat skenario penggunaan keyword global dan nonlocal secara langsung.
· 8 mnt Baca

Jelajahi bersama AI

Melihat pesan “name is not defined” atau “local variable referenced before assignment” setelah menulis beberapa baris kode itu menjengkelkan. Kodenya terlihat baik, namun Python tidak sependapat. Penyebab utamanya hampir selalu soal cakupan (scope): di mana sebuah nama terlihat dan ke objek mana ia merujuk pada saat itu.

Begitu Anda memahami cara pencarian nama di Python—sering diringkas sebagai aturan LEGB—kesalahan ini menjadi dapat diprediksi dan mudah diperbaiki. Dalam tutorial ini, saya akan membahas variabel dan cakupan di Python selangkah demi selangkah.

Apa Itu Variabel?

Variabel adalah nama yang diikat ke sebuah objek. Di Python, Anda membuat ikatan dengan operator penugasan =. Nama tidak bertipe; nama dapat menunjuk ke objek apa pun (string, int, list, function, dan sebagainya).

customer_name = "Ava Torres"
order_count = 1
total_cents = 1 + 2 * 300  # evaluated first, then bound

Ikuti aturan dan konvensi ini saat memberi nama variabel untuk menghindari error sintaks dan bug tersembunyi.

  • Gunakan huruf, angka, dan garis bawah saja; nama tidak boleh diawali angka.
  • Jangan gunakan keyword seperti True, for, atau class sebagai nama.
  • Hindari membayangi (shadowing) built-in seperti list, dict, sum, atau max.
  • Gunakan snake_case demi keterbacaan (PEP 8).

Contoh berikut memperlihatkan apa yang tidak boleh dilakukan dan error yang akan muncul di Python:

first string value = "First string"  # spaces not allowed
# SyntaxError: invalid syntax

1st_value = 10  # cannot start with a digit
# SyntaxError: invalid decimal literal

True = "yes"  # cannot assign to a keyword
# SyntaxError: cannot assign to True

Cara Kerja Scope Python (LEGB)

Scope adalah wilayah kode tempat sebuah nama terlihat. Saat Anda menggunakan sebuah nama, Python mencarinya dalam urutan berikut (LEGB):

  • Local: scope fungsi saat ini.
  • Enclosing: scope fungsi luar (untuk fungsi bertingkat).
  • Global: tingkat atas modul (namespace modul).
  • Built-in: nama yang didefinisikan oleh Python di builtins (misalnya, len, print).

Nama hidup di dalam namespace (anggaplah sebagai kamus yang memetakan nama ke objek). Scope menentukan namespace mana yang dirujuk Python untuk menyelesaikan sebuah nama pada titik tertentu di kode.

Scope lokal

Nama yang ditugaskan di dalam fungsi bersifat lokal untuk fungsi itu kecuali dinyatakan lain. Nama tersebut tidak terlihat di luar fungsi.

def show_order_id():
    order_id = 42
    print("inside function:", order_id)

show_order_id()
print("outside function:", order_id)  # NameError

Python memutuskan scope saat kompilasi. Jika sebuah fungsi melakukan penugasan ke sebuah nama di mana pun di tubuhnya, semua penggunaan nama tersebut di fungsi dianggap lokal—menyebabkan UnboundLocalError umum ketika Anda membaca sebelum menugaskan:

discount_rate = 0.10  # module-level (global)

def price_with_discount(amount_cents):
    print("configured discount:", discount_rate)  # looks local because of the assignment below
    discount_rate = 0.20  # assignment makes 'discount_rate' local in this function
    return int(amount_cents * (1 - discount_rate))

# UnboundLocalError: cannot access local variable 'discount_rate' where it is not associated with a value

Untuk menggunakan nama tingkat modul di dalam fungsi, hindari menugaskannya atau tandai sebagai global (dibahas di bawah).

Scope enclosing (closure)

Fungsi bertingkat dapat melihat nama dari fungsi yang langsung melingkupinya. Untuk mengikat ulang nama tersebut (bukan sekadar membacanya), nyatakan sebagai nonlocal.

def make_step_counter():
    count = 0  # enclosing scope for 'increment'

    def increment():
        nonlocal count  # rebind the 'count' in the nearest enclosing function
        count += 1
        return count

    return increment

step = make_step_counter()
print(step())  # 1
print(step())  # 2

Tanpa nonlocal, penugasan ke count di dalam increment() akan membuat nama lokal baru dan membiarkan count luar tidak berubah.

Scope global

Nama yang ditugaskan di tingkat atas modul berada di namespace global modul. Fungsi mana pun dapat membacanya. Untuk menugaskan ke nama tingkat modul dari dalam fungsi, nyatakan sebagai global.

greeting = "Hello"

def greet_city(city_name):
    print(greeting, city_name)  # reads global

def set_greeting(new_greeting):
    global greeting
    greeting = new_greeting     # rebinds global

greet_city("Nairobi")  # Hello Nairobi
set_greeting("Hi")
greet_city("Nairobi")  # Hi Nairobi

Gunakan global secara hemat. Lebih baik meneruskan nilai sebagai parameter dan mengembalikan hasil agar kode tetap mudah diuji dan diprediksi.

Scope built-in (dan catatan tentang keyword)

Scope built-in berisi nama seperti len, print, dan Exception. Hindari membayangi nama-nama ini, jika tidak Anda akan kehilangan akses ke built-in tersebut pada scope itu.

list = [1, 2, 3]     # shadows the built-in 'list' constructor
list("abc")          # TypeError: 'list' object is not callable
del list             # fix by deleting the shadowing name

Keyword (seperti if, for, def) adalah bagian dari sintaks Python, bukan namespace built-in, dan tidak pernah dapat digunakan sebagai identifier.

Blok, Loop, dan Comprehension

Pernyataan blok dan comprehension di Python memiliki perilaku scoping khusus yang sering mengejutkan pengembang dari bahasa lain.

Tidak ada scope blok untuk if/for/while/with

Penugasan di dalam blok-blok ini memengaruhi scope yang menaunginya (fungsi atau modul). Variabel loop juga tetap terdefinisi setelah loop berakhir.

if True:
    status = "ready"
print(status)  # "ready"

for i in range(3):
    pass
print(i)  # 2 (the last value from the loop)

Comprehension mengisolasi variabel iterasinya

List, dict, dan set comprehension memiliki scope lokal sendiri untuk variabel loop. Variabel iterasi tidak bocor ke scope di sekitarnya.

numbers = [1, 2, 3]
[x for x in numbers]
print("x" in globals() or "x" in locals())  # False

Python 3.12 (PEP 709) melakukan inline comprehension demi kecepatan sambil mempertahankan isolasi ini; Anda tetap mendapatkan variabel loop yang jelas dan tidak bocor dengan eksekusi yang lebih cepat.

Menggunakan Keyword global

Nyatakan sebuah nama sebagai global di dalam fungsi saat Anda perlu mengikat ulang variabel tingkat modul. Letakkan deklarasi di dekat awal fungsi agar jelas variabel mana yang Anda ubah.

tax_rate = 0.08

def configure_tax(rate):
    global tax_rate
    tax_rate = float(rate)

def total_with_tax(cents):
    return int(cents * (1 + tax_rate))

configure_tax(0.10)
print(total_with_tax(1000))  # 1100

Menggunakan Keyword nonlocal

Gunakan nonlocal untuk mengikat ulang sebuah nama dari scope fungsi terdekat yang melingkupinya. Ini umum pada closure yang mempertahankan state.

def make_accumulator(start=0):
    total = start
    def add(amount):
        nonlocal total
        total += amount
        return total
    return add

acc = make_accumulator()
print(acc(5))   # 5
print(acc(10))  # 15

Menggunakan nonlocal untuk nama yang tidak didefinisikan di fungsi yang melingkupi adalah SyntaxError. Jika namanya global, gunakan global.

locals() dan globals() pada 2025

Fungsi-fungsi ini berguna untuk inspeksi dan debugging, bukan untuk memperbarui variabel. Mulai Python 3.13 (PEP 667), setiap pemanggilan locals() di dalam fungsi mengembalikan snapshot independen. Mengedit snapshot tersebut tidak mengubah variabel lokal sesungguhnya. Saya mengonfirmasi perilaku ini dengan menjalankan cuplikan berikut pada Python 3.13:

def probe():
    project = "alpha"
    snap1 = locals()
    snap1["project"] = "beta"  # edits the snapshot only
    observed = project         # still "alpha"
    snap2 = locals()           # new snapshot
    return snap1["project"], observed, snap2["project"]

print(probe())  # ('beta', 'alpha', 'alpha')

Gunakan globals() dengan cara serupa untuk namespace modul. Saat menulis kode aplikasi, lebih utamakan parameter dan nilai kembalian eksplisit daripada pencarian dinamis.

Kesalahan Umum dan Cara Memperbaikinya

Kesalahan-kesalahan ini menyumbang sebagian besar error terkait scope yang saya lihat di praktik.

  • UnboundLocalError akibat penugasan di dalam fungsi: Python menganggap sebuah nama sebagai lokal jika ditugaskan di mana pun dalam fungsi. Pindahkan pembacaan setelah penugasan, ganti nama, atau tambahkan global/nonlocal sesuai kebutuhan.
  • Berharap ada scope blok: Nama yang ditugaskan di if/for/while/with tetap ada di scope yang menaunginya. Gunakan fungsi pembantu yang lebih sempit untuk membatasi scope.
  • Membayangi built-in: Hindari nama seperti list, dict, sum, id, atau min. Pilih nama deskriptif seperti customer_list atau min_allowed.
  • Lupa nonlocal di closure: Jika Anda bermaksud memperbarui variabel fungsi luar, nyatakan sebagai nonlocal. Jika tidak, Anda membuat lokal baru dan nilai luar tidak berubah.
  • Membingungkan keyword dengan built-in: Keyword (sintaks) tidak pernah bisa digunakan sebagai nama. Built-in bisa dibayangi tetapi sebaiknya dihindari.

Praktik Terbaik agar Scope Tetap Sederhana

Kebiasaan-kebiasaan ini membuat kode lebih mudah dibaca, diuji, dan di-debug.

  • Utamakan fungsi kecil dan terfokus. Definisikan variabel pada scope tersempit yang memungkinkan.
  • Lewatkan data masuk dan keluar melalui parameter dan nilai kembalian. Minimalkan state tingkat modul.
  • Gunakan closure secara sengaja. Dokumentasikan nama luar mana yang ditangkap fungsi bertingkat, dan gunakan nonlocal hanya saat benar-benar perlu mengikat ulang.
  • Pilih nama yang deskriptif dan tidak berbenturan. Garis bawah di depan (misalnya, _cache) menandakan penggunaan internal.
  • Perlakukan locals()/globals() sebagai diagnostik read-only, bukan mekanisme konfigurasi.

Kesimpulan

Python menyelesaikan nama dengan mencari dari Local → Enclosing → Global → Built-in. Memahami urutan itu—dan kapan menggunakan global atau nonlocal—menghilangkan kesalahan umum seperti NameError dan UnboundLocalError. Simpan variabel pada scope sekecil mungkin, hindari membayangi built-in, dan gunakan closure secara terukur. Dengan model mental itu, fungsi Anda berperilaku dapat diprediksi, dan scope tidak lagi menjadi sumber kejutan.

Sejal Jaiswal

Penulis

Sejal Jaiswal

Saya telah bekerja di berbagai industri dan mengenakan banyak peran: pengembang perangkat lunak, peneliti machine learning, ilmuwan data, manajer produk. Namun pada intinya, saya adalah seorang programmer yang gemar belajar dan berbagi pengetahuan!

Topik

Terkait

blogs

Spaghetti Plot dan Jalur Badai

blogs

Tutorial Korelasi di R

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026