Pernyataan nonlokal Python

341

Apa yang dilakukan nonlocalpernyataan Python (dalam Python 3.0 dan yang lebih baru)?

Tidak ada dokumentasi di situs web resmi Python dan help("nonlocal")juga tidak berfungsi.

ooboo
sumber
4
Lihatlah pertanyaan ini: stackoverflow.com/questions/1414304/local-functions-in-python
Matt Joiner
18
Berikut adalah dokumentasi situs web resmi Python untuk nonlokal: docs.python.org/3/reference/… (dokumentasi ini telah tersedia sejak Python 3.0, sehingga pernyataan OP bahwa tidak ada dokumentasi resmi salah)
wkschwartz
3
"There is no documentation for nonlocal".Sebenarnya, Anda dapat melakukannya help(keyword_in_string)untuk dokumentasi dengan Python 3 ke atas
ytpillai
10
Agar adil, dokumen resmi agak menyedot masalah itu. Contoh jawaban yang dipilih membuat semuanya menjadi sangat jelas, menjadikannya pertanyaan yang berharga.
Fisikawan Gila

Jawaban:

473

Bandingkan ini, tanpa menggunakan nonlocal:

x = 0
def outer():
    x = 1
    def inner():
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 0

Untuk ini, menggunakan nonlocal, di mana inner()'s xsekarang juga outer()' s x:

x = 0
def outer():
    x = 1
    def inner():
        nonlocal x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 2
# global: 0

Jika kita menggunakannya global, itu akan mengikat xnilai "global" yang benar:

x = 0
def outer():
    x = 1
    def inner():
        global x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 2
Segera
sumber
32
Bagaimana itu berbeda dari global x?
ooboo
52
Sangat mirip - tetapi perhatikan bahwa x luar tidak mendunia dalam contoh tetapi didefinisikan dalam fungsi luar.
Anon
3
@Dustin - Sebenarnya, jika Anda memiliki kelas A dengan atribut x dan subclass B yang didefinisikan di dalamnya, Anda akan merujuk ke x dari dalam B sebagai Ax
Anon
2
Kode mudah mendapatkan indentasi ketika mendefinisikan fungsi dalam dan akhirnya melanggar rekomendasi 79 chars PEP8. Adakah cara untuk mengatasi masalah ini? Dapatkah fungsi bagian dalam ditempatkan di luar fungsi bagian luar? Saya tahu pertanyaannya terdengar bodoh, tapi saya sungguh-sungguh.
tommy.carstensen
3
@ tommy.carstensen Anda bisa melewati fungsi sebagai argumen itulah keindahan fungsi tingkat tinggi. Juga dalam pemrograman fungsional ini disebut komposisi, python bukan bahasa FP murni tetapi Anda tentu bisa bermain dengan fitur (generator, fungsi urutan yang lebih tinggi adalah beberapa contoh)
superuseroi
90

Singkatnya, ini memungkinkan Anda menetapkan nilai ke variabel dalam lingkup luar (tetapi non-global). Lihat PEP 3104 untuk semua detail berdarah.

Arkady
sumber
41

Pencarian google untuk "python nonlocal" muncul Proposal, PEP 3104 , yang sepenuhnya menggambarkan sintaks dan alasan di balik pernyataan itu. singkatnya, ia bekerja dengan cara yang persis sama dengan globalpernyataan, kecuali bahwa ia digunakan untuk merujuk ke variabel yang tidak global atau lokal ke fungsi.

Inilah contoh singkat tentang apa yang dapat Anda lakukan dengan ini. Penghitung generator dapat ditulis ulang untuk menggunakan ini sehingga lebih mirip idiom bahasa dengan penutup.

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

Jelas, Anda dapat menulis ini sebagai generator, seperti:

def counter_generator():
    count = 0
    while True:
        count += 1
        yield count

Tapi sementara ini adalah python idiomatis, tampaknya versi pertama akan sedikit lebih jelas bagi pemula. Menggunakan generator dengan benar, dengan memanggil fungsi yang dikembalikan, adalah titik kebingungan yang umum. Versi pertama secara eksplisit mengembalikan fungsi.

SingleNegationElimination
sumber
1
Saya yakin itulah yang dilakukan kata kunci 'global' - bekerja dengan lingkungan yang lebih tinggi hingga mencapai variabel dengan nama itu. variabel x dapat dideklarasikan pada level modul, di dalam kelas, lalu secara terpisah di dalam fungsi di dalam kelas ini dan kemudian di dalam fungsi fungsi tersebut - bagaimana ia tahu x mana yang harus dirujuk?
ooboo
7
hal tentang global adalah ia hanya berfungsi untuk variabel global. itu tidak bisa melihat variabel dalam lingkup nonglobal, melampirkan.
SingleNegationElimination
Saya mencoba make_counter - namun tidak mengembalikan generator tetapi fungsi. apakah ada cara untuk mengembalikan generator sehingga nanti saya bisa beralih lagi?
Dejell
@ Dubel: contoh ini dimaksudkan untuk menggambarkan nonlocalpernyataan dengan Python; Jika Anda ingin urutan bilangan asli, idiom python sebenarnyaitertools.count()
SingleNegationElimination
Saya ingin menunjukkan kemampuan untuk mengembalikan generator seperti dengan hasil - hasil sebenarnya mengembalikan generator. Ide saya bukan menggunakan hasil dan mungkin menggunakan nonlocal atau solusi lain
Dejell
15

@ooboo:

Dibutuhkan satu "paling dekat" ke titik referensi dalam kode sumber. Ini disebut "Lexical Scoping" dan standar untuk> 40 tahun sekarang.

Anggota kelas Python benar-benar ada dalam kamus yang disebut __dict__dan tidak akan pernah dijangkau oleh pelingkupan leksikal.

Jika Anda tidak menentukan nonlocaltetapi melakukannya x = 7, itu akan membuat variabel lokal baru "x". Jika Anda menentukan nonlocal, itu akan menemukan "terdekat" "x" dan menetapkan itu. Jika Anda menentukan nonlocaldan tidak ada "x", itu akan memberi Anda pesan kesalahan.

Kata kunci globalselalu terasa aneh bagi saya karena dengan senang hati akan mengabaikan semua "x" lainnya kecuali yang terluar. Aneh.

Danny Milosavljevic
sumber
14

help ('nonlocal') nonlocalPernyataan itu


    nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*

The nonlocalpernyataan menyebabkan pengidentifikasi terdaftar untuk merujuk pada variabel yang sebelumnya terikat dalam lingkup melampirkan terdekat. Ini penting karena perilaku default untuk mengikat adalah mencari terlebih dahulu namespace lokal. Pernyataan ini memungkinkan kode enkapsulasi untuk mengubah variabel di luar lingkup lokal selain lingkup global (modul).

Nama-nama yang tercantum dalam nonlocalpernyataan, tidak seperti yang tercantum dalam globalpernyataan, harus merujuk ke binding yang sudah ada sebelumnya dalam lingkup terlampir (lingkup di mana ikatan baru harus dibuat tidak dapat ditentukan secara jelas).

Nama-nama yang tercantum dalam nonlocalpernyataan tidak boleh bertabrakan dengan ikatan yang sudah ada sebelumnya dalam lingkup lokal.

Lihat juga:

PEP 3104 - Akses ke Nama di Lingkup Luar
Spesifikasi untuk nonlocalpernyataan.

Topik bantuan terkait: global, NAMESPACES

Sumber: Referensi Bahasa Python

Yossi Truzman
sumber
11
Pelajari sesuatu yang baru setiap hari. Saya tidak tahu Anda bisa menggunakan help()kata kunci (dan sekarang pikiran saya meledak: help()tanpa argumen menjadi interaktif ).
Erik Youngren
6

Kutipan dari Python 3 Referensi :

Pernyataan nonlokal menyebabkan pengidentifikasi terdaftar untuk merujuk ke variabel terikat sebelumnya dalam cakupan terlampir terdekat tidak termasuk global.

Seperti yang disebutkan dalam referensi, dalam kasus beberapa fungsi bersarang hanya variabel dalam fungsi terlampir terdekat yang dimodifikasi:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        x = 2
        innermost()
        if x == 3: print('Inner x has been modified')

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Inner x has been modified

Variabel "terdekat" dapat berjarak beberapa tingkat:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Outer x has been modified

Tapi itu tidak bisa menjadi variabel global:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    inner()

x = 0
outer()
if x == 3: print('Global x has been modified')

# SyntaxError: no binding for nonlocal 'x' found
Jeyekomon
sumber
3
a = 0    #1. global variable with respect to every function in program

def f():
    a = 0          #2. nonlocal with respect to function g
    def g():
        nonlocal a
        a=a+1
        print("The value of 'a' using nonlocal is ", a)
    def h():
        global a               #3. using global variable
        a=a+5
        print("The value of a using global is ", a)
    def i():
        a = 0              #4. variable separated from all others
        print("The value of 'a' inside a function is ", a)

    g()
    h()
    i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)
gxyd
sumber
2

Pemahaman pribadi saya tentang pernyataan "nonlokal" (dan permisi karena saya baru mengenal Python dan Pemrograman secara umum) adalah bahwa "nonlokal" adalah cara untuk menggunakan fungsionalitas Global dalam fungsi yang diulang daripada tubuh kode itu sendiri . Pernyataan global antar fungsi jika Anda mau.

Yossi Truzman
sumber
0

dengan fungsi bagian dalam 'nonlokal' (mis. fungsi bagian dalam bersarang) dapat memperoleh izin baca & ' tulis ' untuk variabel tertentu dari fungsi induk luar . Dan nonlocal hanya dapat digunakan di dalam fungsi dalam misalnya:

a = 10
def Outer(msg):
    a = 20
    b = 30
    def Inner():
        c = 50
        d = 60
        print("MU LCL =",locals())
        nonlocal a
        a = 100
        ans = a+c
        print("Hello from Inner",ans)       
        print("value of a Inner : ",a)
    Inner()
    print("value of a Outer : ",a)

res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
NIPHIN
sumber