Scurtă descriere a normelor de definire a domeniului de aplicare? (Programare, Python, Domeniu De Aplicare, Limbaje Dinamice)

Charles Merriam a intrebat.

Ce este exact sunt regulile de definire a domeniului de aplicare Python?

Dacă am un cod:

code1
class Foo:
   code2
   def spam.....
      code3
      for code4..:
       code5
       x()

Unde este x se găsește? Unele dintre opțiunile posibile includ lista de mai jos:

  1. În fișierul sursă aferent
  2. În spațiul de nume al clasei
  3. În definiția funcției
  4. În variabila index a buclei for
  5. În interiorul buclei for

Există, de asemenea, contextul din timpul execuției, atunci când funcția spam este transmisă în altă parte. Și poate că funcții lambda trec un pic diferit?

Trebuie să existe o referință sau un algoritm simplu undeva. Este o lume confuză pentru programatorii Python intermediari.

Comentarii

  • Regulile de încadrare sunt descrise destul de laconic – dar și complet – în documentația Python: docs.python.org/3/reference/…. –  > Por jefe2000.
9 răspunsuri
Rizwan Kassim

De fapt, o regulă concisă pentru rezoluția Python Scope, din Learning Python, 3rd. Ed. (Aceste reguli sunt specifice numelor de variabile, nu atributelor. Dacă faceți referire la ea fără punct, se aplică aceste reguli).

Regula LEGB

  • Local – Numele atribuite în orice mod în cadrul unei funcții (def sau lambda), și care nu sunt declarate globale în acea funcție

  • Enclosing-function – Denumiri atribuite în domeniul de aplicare local al oricărei și tuturor funcțiilor statice închise (def sau lambda), de la interior la exterior

  • Global (modul) – Nume atribuite la nivelul superior al unui fișier de modul sau prin executarea unei funcții global într-o instrucțiune def în cadrul fișierului

  • Built-in (Python) – Nume preasemnate în modulul de nume încorporate: open, , range, , SyntaxError, , etc.

Astfel, în cazul lui

code1
class Foo:
    code2
    def spam():
        code3
        for code4:
            code5
            x()

for bucla nu are un spațiu de nume propriu. În ordinea LEGB, domeniile de cuprindere ar fi

  • L: Local în def spam (în code3, , code4, , și code5)
  • E: Orice funcție de închidere (dacă întregul exemplu ar fi în altă parte). def)
  • G: Au existat x declarate la nivel global în modul (în code1)?
  • B: Orice funcție încorporată x în Python.

x nu se va găsi niciodată în code2 (chiar și în cazurile în care v-ați aștepta să o facă, vezi răspunsul lui Antti sau aici).

Comentarii

    47

  • Ca o atenționare la Accesul global – citirea unei variabile globale poate avea loc fără o declarație explicită, dar scrierea în ea fără a declara global(var_name) va crea în schimb o nouă instanță locală. –  > Por Peter Gibson.
  • De fapt, @Peter, global(var_name) este incorect din punct de vedere sintactic. Sintaxa corectă ar fi global var_name fără paranteze. Aveți totuși un punct de vedere valabil. –  > Por martineau.
  • Dacă este așa, atunci de ce variabila „y” a lui foo nu este vizibilă pentru „bar” de mai jos: >>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3 –  > Por Jonathan Mayer.
  • @Jonathan: Pentru că fiecare y este scrisă și nu există global y declarații – a se vedea comentariul lui @Peter. –  > Por martineau.
  • @Ctrl-C Nu chiar; nu există nimic special despre atributele de clasă în ceea ce privește domeniul de aplicare. Ele sunt partajate în sensul că self.someClassAttribute se vor referi la același obiect indiferent de instanța self se referă, dar numele în sine trebuie să fie folosit ca atribut pe o instanță sau pe clasa însăși. Comportamentul special real este că în timpul evaluării instrucțiunilor în corpul clasei, atributul de clasă va umbri toate variabilele existente în domeniul de cuprindere. De exemplu j = 0; class Foo: j = 3; print(j); # end of class; print(j) va produce 3, apoi 0. –  > Por chepner.
Brian

În esență, singurul lucru din Python care introduce un nou domeniu de aplicare este o definiție de funcție. Clasele sunt un caz un pic mai special, în sensul că orice lucru definit direct în corp este plasat în spațiul de nume al clasei, dar nu sunt direct accesibile din interiorul metodelor (sau al claselor imbricate) pe care le conțin.

În exemplul dvs. există doar 3 sfere în care va fi căutat x:

  • domeniul de aplicare al spam-ului – care conține tot ceea ce este definit în code3 și code5 (precum și code4, variabila dvs. de buclă).

  • Domeniul global – care conține tot ceea ce este definit în code1, precum și Foo (și tot ceea ce se modifică după el)

  • Spațiul de nume builtins. Un caz puțin special – acesta conține diversele funcții și tipuri Python builtin, cum ar fi len() și str(). În general, acesta nu ar trebui să fie modificat de niciun cod utilizator, așa că este de așteptat să conțină funcțiile standard și nimic altceva.

Mai multe domenii de aplicare apar doar atunci când introduceți o funcție imbricata (sau lambda) în imagine.Totuși, acestea se vor comporta cam așa cum v-ați aștepta. Funcția imbricata poate accesa tot ceea ce se află în domeniul de aplicare local, precum și tot ceea ce se află în domeniul de aplicare al funcției care o înconjoară. ex.

def foo():
    x=4
    def bar():
        print x  # Accesses x from foo's scope
    bar()  # Prints 4
    x=5
    bar()  # Prints 5

Restricții:

Variabilele din alte domenii decât variabilele funcției locale pot fi accesate, dar nu pot fi transformate în parametri noi fără o sintaxă suplimentară. În schimb, atribuirea va crea un nou parametru local variabilă nouă în loc să afecteze variabila din domeniul de aplicare părinte. De exemplu:

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It's just accessing, not rebinding
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Again, this doen't affect func's local1 variable.  It creates a 
        # new local variable also called local1 instead.
        local1 = 5
        print local1

    embedded_func() # Prints 5
    print local1    # Prints 4

Pentru a modifica efectiv legăturile variabilelor globale din cadrul unei funcții, trebuie să specificați că variabila este globală cu ajutorul cuvântului cheie global. De exemplu:

global_var = 4
def change_global():
    global global_var
    global_var = global_var + 1

În prezent, nu există nicio modalitate de a face același lucru pentru variabilele din cadrul unui context de tip „enclosing”. dar Python 3 introduce un nou cuvânt cheie, „nonlocal„, care va acționa într-un mod similar cu global, dar pentru sferele de funcții imbricate.

Antti Haapala

Nu a existat un răspuns detaliat cu privire la timpul Python3, așa că am făcut un răspuns aici. Cea mai mare parte din ceea ce este descris aici este detaliat în documentul 4.2.2 Rezolvarea numelor din documentația Python 3.

Așa cum s-a furnizat în alte răspunsuri, există 4 domenii de bază, LEGB, pentru Local, Enclosing, Global și Builtin. În plus față de acestea, există un domeniu de aplicare special, domeniul de aplicare corpul clasei, , care nu cuprinde un domeniu de cuprindere pentru metodele definite în cadrul clasei; orice atribuire în cadrul corpului clasei face ca variabila de acolo încolo să fie legată în corpul clasei.

În special, nu în afară de def și class, , creează un domeniu de cuprindere a variabilei. În Python 2, o înțelegere de listă nu creează un domeniu de variabilă, însă în Python 3 variabila de buclă din cadrul înțelegerilor de listă este creată într-un nou domeniu.

Pentru a demonstra particularitățile corpului clasei

x = 0
class X(object):
    y = x
    x = x + 1 # x is now a variable
    z = x

    def method(self):
        print(self.x) # -> 1
        print(x)      # -> 0, the global x
        print(y)      # -> NameError: global name 'y' is not defined

inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)

Astfel, spre deosebire de corpul funcției, în corpul clasei puteți realoca variabila cu același nume pentru a obține o variabilă de clasă cu același nume; căutările ulterioare pe acest nume se rezolvă în schimb la variabila de clasă.


Una dintre cele mai mari surprize pentru mulți nou-veniți în Python este faptul că o clasă for bucla nu creează un domeniu de variabilă. În Python 2, nici comprehensiunile de liste nu creează un domeniu de cuprindere (în timp ce generatoarele și comprehensiunile dict o fac!) În schimb, acestea scurg valoarea în funcție sau în domeniul global:

>>> [ i for i in range(5) ]
>>> i
4

Comprehensiunile pot fi folosite ca o modalitate vicleană (sau îngrozitoare, dacă doriți) de a crea variabile modificabile în cadrul expresiilor lambda în Python 2 – o expresie lambda creează o sferă de variabilă, cum ar fi def ar face-o, dar în cadrul unei expresii lambda nu sunt permise declarații. Faptul că atribuirea este o declarație în Python înseamnă că nu sunt permise atribuiri de variabile în lambda, dar o înțelegere a unei liste este o expresie…

Acest comportament a fost corectat în Python 3 – nu mai există expresii de înțelegere sau generatoare de variabile de scurgere.


Global înseamnă de fapt domeniul de aplicare al modulului; modulul principal python este modulul __main__; toate modulele importate sunt accesibile prin intermediul sys.modules variabila; pentru a avea acces la __main__ se poate folosi sys.modules['__main__'], , sau import __main__; este perfect acceptabil să accesați și să atribuiți atribute acolo; acestea vor apărea ca variabile în domeniul global al modulului principal.


Dacă un nume este vreodată atribuit în domeniul curent (cu excepția domeniului de clasă), se va considera că aparține acelui domeniu; în caz contrar, se va considera că aparține oricărui domeniu învecinat care atribuie variabila (s-ar putea să nu fie atribuită încă sau deloc) sau, în cele din urmă, domeniului global. În cazul în care variabila este considerată locală, dar nu este încă setată sau a fost ștearsă, citirea valorii variabilei va avea ca rezultat UnboundLocalError, , care este o subclasă de NameError.

x = 5
def foobar():
    print(x)  # causes UnboundLocalError!
    x += 1    # because assignment here makes x a local variable within the function

# call the function
foobar()

Domeniul de aplicare poate declara că dorește în mod explicit să modifice variabila globală (domeniul de aplicare al modulului), cu ajutorul cuvântului cheie global:

x = 5
def foobar():
    global x
    print(x)
    x += 1

foobar() # -> 5
print(x) # -> 6

Acest lucru este posibil chiar și în cazul în care a fost umbrită în domeniul de aplicare care o înconjoară:

x = 5
y = 13
def make_closure():
    x = 42
    y = 911
    def func():
        global x # sees the global value
        print(x, y)
        x += 1

    return func

func = make_closure()
func()      # -> 5 911
print(x, y) # -> 6 13

În python 2 nu există o modalitate ușoară de a modifica valoarea din domeniul de cuprindere învecinat; de obicei, acest lucru este simulat prin existența unei valori mutabile, cum ar fi o listă cu lungimea de 1:

def make_closure():
    value = [0]
    def get_next_value():
        value[0] += 1
        return value[0]

    return get_next_value

get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2

Cu toate acestea, în python 3, se poate utiliza nonlocal vine în ajutor:

def make_closure():
    value = 0
    def get_next_value():
        nonlocal value
        value += 1
        return value
    return get_next_value

get_next = make_closure() # identical behavior to the previous example.

nonlocal documentație spune că

Numele listate într-o instrucțiune nelocală, spre deosebire de cele listate într-o instrucțiune globală, trebuie să se refere la legături preexistente într-un domeniu de cuprindere (domeniul de cuprindere în care trebuie creată o nouă legătură nu poate fi determinat fără ambiguitate).

De exemplu nonlocal se referă întotdeauna la cel mai interior domeniu exterior non-global în care numele a fost legat (adică atribuit la, inclusiv utilizat ca for variabilă țintă, în with sau ca parametru de funcție).


Orice variabilă care nu este considerată a fi locală pentru domeniul curent sau pentru orice domeniu înconjurător este o variabilă globală. Un nume global este căutat în dicționarul global al modulului; dacă nu este găsit, globalul este apoi căutat în modulul builtins; numele modulului a fost schimbat de la python 2 la python 3; în python 2 era __builtin__ iar în python 3 se numește acum builtins. Dacă atribuiți un atribut din modulul builtins, acesta va fi vizibil ulterior oricărui modul ca variabilă globală lizibilă, cu excepția cazului în care modulul respectiv le umbrește cu propria variabilă globală cu același nume.


Citirea modulului builtins poate fi, de asemenea, utilă; să presupunem că doriți funcția de tipărire în stilul python 3 în unele părți ale fișierului, dar alte părți ale fișierului folosesc în continuare funcția print declarație. În Python 2.6-2.7 puteți face rost de modulul Python 3 print cu:

import __builtin__

print3 = __builtin__.__dict__['print']

from __future__ import print_function de fapt nu importă funcția print nicăieri în Python 2 – în schimb, doar dezactivează regulile de analiză pentru print în modulul curent, gestionând print ca orice alt identificator de variabilă, permițând astfel utilizarea funcției print funcția să fie căutată în builtins.

brianray

Un exemplu ceva mai complet de domeniu de aplicare:

from __future__ import print_function  # for python 2 support

x = 100
print("1. Global x:", x)
class Test(object):
    y = x
    print("2. Enclosed y:", y)
    x = x + 1
    print("3. Enclosed x:", x)

    def method(self):
        print("4. Enclosed self.x", self.x)
        print("5. Global x", x)
        try:
            print(y)
        except NameError as e:
            print("6.", e)

    def method_local_ref(self):
        try:
            print(x)
        except UnboundLocalError as e:
            print("7.", e)
        x = 200 # causing 7 because has same name
        print("8. Local x", x)

inst = Test()
inst.method()
inst.method_local_ref()

ieșire:

1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200

Comentarii

  • Acesta este un răspuns excelent. Cu toate acestea, cred că diferențele dintre method și method_local_ref ar trebui să fie evidențiate. method este capabil să acceseze variabila globală și să o tipărească ca în 5. Global x. Dar method_local_ref nu poate, deoarece mai târziu definește o variabilă locală cu același nume. Puteți testa acest lucru prin eliminarea variabilei x = 200 și să vedeți diferența –  > Por kiril.
  • @brianray: Ce zici de z? –  > Por Malik A. Rumi.
  • @kiril Am adăugat o notă despre asta –  > Por brianray.
  • @MalikA.Rumi Am eliminat z, deoarece nu era interesant –  > Por brianray.
  • În mod surprinzător, acesta este singurul explicație clară a sferelor Python, pe care am putut-o găsi pe toate SO. Folosind pur și simplu un exemplu foarte simplu. Mulțumesc! –  > Por not2qubit.
Jeremy Cantrell

Regulile de încadrare pentru Python 2.x au fost deja prezentate în alte răspunsuri. Singurul lucru pe care l-aș adăuga este că, în Python 3.0, există și conceptul de domeniu de aplicare non-local (indicat prin cuvântul cheie „nonlocal”). Acest lucru vă permite să accesați direct sferele exterioare și vă oferă posibilitatea de a face unele trucuri frumoase, inclusiv închideri lexicale (fără hack-uri urâte care implică obiecte mutabile).

EDIT: Aici este PEP cu mai multe informații în acest sens.

S.Lott

Python rezolvă variabilele cu — în general — trei spații de nume disponibile.

În orice moment în timpul execuției, există cel puțin trei domenii de cuprindere imbricate ale căror spații de nume sunt direct accesibile: domeniul de cuprindere cel mai interior, care este căutat primul, conține numele locale; spațiile de nume ale oricăror funcții închise, care sunt căutate începând cu cel mai apropiat domeniu de cuprindere; domeniul de cuprindere din mijloc, căutat în continuare, conține numele globale ale modulului curent; iar domeniul de cuprindere cel mai exterior (căutat ultimul) este spațiul de nume care conține numele încorporate.

Există două funcții: globals și locals care vă arată conținutul a două dintre aceste spații de nume.

Spațiile de nume sunt create de pachete, module, clase, construcții de obiecte și funcții. Nu există alte variante de spații de nume.

În acest caz, apelul către o funcție numită x trebuie să fie rezolvată în spațiul de nume local sau în spațiul de nume global.

Local în acest caz, este corpul funcției metodei Foo.spam.

Global este – ei bine – global.

Regula este de a căuta în spațiile locale imbricate create de funcțiile metodei (și definițiile funcțiilor imbricate), apoi de a căuta în spațiul global. Asta este tot.

Nu există alte domenii de aplicare. for (și alte instrucțiuni compuse precum if și try) nu creează noi domenii de aplicare imbricate. Doar definițiile (pachete, module, funcții, clase și instanțe de obiecte.)

În interiorul unei definiții de clasă, numele fac parte din spațiul de nume al clasei. code2, , de exemplu, trebuie să fie calificat de numele clasei. În general, Foo.code2. Cu toate acestea, self.code2 va funcționa, de asemenea, deoarece obiectele Python se uită la clasa care conține clasa ca o soluție de rezervă.

Un obiect (o instanță a unei clase) are variabile de instanță. Aceste nume se află în spațiul de nume al obiectului. Ele trebuie să fie calificate de către obiect. (variable.instance.)

Din interiorul unei metode de clasă, există variabile locale și globale. Se spune self.variable să alegeți instanța ca spațiu de nume. Veți observa că self este un argument pentru fiecare funcție membră a clasei, ceea ce o face parte din spațiul de nume local.

A se vedea Reguli Python Scope, , Python Scope, Domeniul de aplicare al variabilelor.

Comentarii

  • Acest lucru este depășit. Începând cu versiunea 2.1 (acum 7 ani), există mai mult de două domenii de cuprindere, deoarece funcțiile imbricate introduc noi domenii de cuprindere, astfel încât o funcție în cadrul unei funcții va avea acces la domeniul său de cuprindere local, la domeniul de cuprindere al funcțiilor care o înconjoară și la domeniul de cuprindere global (de asemenea, builtins). –  > Por Brian.
  • Îmi pare rău, nu mai este cazul. Python has two namespaces available. Global and local-to-something. –  > Por Rizwan Kassim.
bobince

Unde se găsește x?

x nu se găsește deoarece nu l-ați definit. 🙂 Ar putea fi găsit în code1 (global) sau code3 (local) dacă îl pui acolo.

code2 (membrii clasei) nu sunt vizibili pentru codul din interiorul metodelor aceleiași clase – de obicei, le accesezi folosind self. code4/code5 (bucle) se află în același domeniu de aplicare ca și code3, așa că dacă ai scrie la x acolo, ai modifica instanța x definită în code3, nu ai crea un nou x.

Python este static, astfel încât, dacă treceți „spam” către o altă funcție, spam va avea în continuare acces la globalii din modulul din care provine (definit în code1) și la orice alte domenii de cuprindere care îl conțin (a se vedea mai jos). membrii code2 ar fi din nou accesați prin self.

lambda nu este diferit de def. Dacă aveți un lambda utilizat în interiorul unei funcții, este același lucru cu definirea unei funcții imbricate. În Python 2.2 și mai departe, sunt disponibile domenii de aplicare imbricate. În acest caz, puteți lega x la orice nivel de înglobare a funcțiilor, iar Python va prelua cea mai interioară instanță:

x= 0
def fun1():
    x= 1
    def fun2():
        x= 2
        def fun3():
            return x
        return fun3()
    return fun2()
print fun1(), x

2 0

fun3 vede instanța x din cel mai apropiat domeniu de cuprindere care îl conține, care este domeniul de cuprindere al funcției asociat cu fun2. Dar celelalte instanțe x, definite în fun1 și la nivel global, nu sunt afectate.

Înainte de nested_scopes – în Python pre-2.1 și în 2.1, și în 2.1, cu excepția cazului în care solicitați în mod specific această caracteristică folosind un from-future-import – fun1 și fun2 nu sunt vizibile pentru fun3, astfel încât răspunsul lui S.Lott este valabil și veți obține x global:

0 0

MisterMiyagi

Rezolvarea numelor Python cunoaște doar următoarele tipuri de domenii de aplicare:

  1. sfera de cuprindere a elementelor construite care furnizează Funcțiile builttin, , cum ar fi print, , int, , sau zip,
  2. modul domeniul de aplicare global care este întotdeauna la nivelul superior al modulului curent,
  3. trei domenii definite de utilizator care pot fi imbricate unul în altul, și anume
    1. funcția domeniul de închidere, din orice domeniu de închidere def bloc, lambda expresie sau înțelegere.
    2. funcție în domeniul local, în interiorul unui def bloc, lambda expresie sau comprehensiune,
    3. clasa în interiorul unui bloc class bloc.

În special, alte construcții, cum ar fi if, , for, , sau with nu au un domeniu de aplicare propriu.

TLDR: The lookup a unui nume începe de la domeniul de cuprindere în care este utilizat numele, apoi de la orice domeniu de cuprindere care îl înconjoară (cu excepția domeniilor de cuprindere ale claselor), la domeniile globale ale modulelor și, în final, la cele ale clădirilor – se utilizează prima potrivire din această ordine de căutare.Se utilizează atribuire la un domeniu de aplicare este în mod implicit la domeniul de aplicare curent – formele speciale nonlocal și global trebuie să fie utilizate pentru atribuirea la un nume dintr-un domeniu de aplicare exterior.

În cele din urmă, comprehensiunile și expresiile generatoare, precum și := expresiile de atribuire au o regulă specială atunci când sunt combinate.


Domenii de cuprindere imbricate și rezolvarea numelor

Aceste domenii de cuprindere diferite construiesc o ierarhie, cu builtins și apoi global formând întotdeauna baza, iar closures, locals și class scope fiind imbricate după cum urmează lexical definite în mod lexical. Adică, numai structurarea în cod sursă contează, nu, de exemplu, stiva de apeluri.

print("builtins are available without definition")

some_global = "1"  # global variables are at module scope

def outer_function():
    some_closure = "3.1"  # locals and closure are defined the same, at function scope
    some_local = "3.2"    # a variable becomes a closure if a nested scope uses it

    class InnerClass:
         some_classvar = "3.3"   # class variables exist *only* at class scope

         def nested_function(self):
             some_local = "3.2"   # locals can replace outer names
             print(some_closure)  # closures are always readable
    return InnerClass

Chiar dacă class creează un domeniu de cuprindere și poate avea clase, funcții și comprehensiuni imbricate, denumirile de class domeniului de aplicare nu sunt vizibile pentru domeniile de aplicare închise. Se creează astfel următoarea ierarhie:

┎ builtins           [print, ...]
┗━┱ globals            [some_global]
  ┗━┱ outer_function     [some_local, some_closure]
    ┣━╾ InnerClass         [some_classvar]
    ┗━╾ inner_function     [some_local]

Rezolvarea numelor începe întotdeauna de la domeniul de aplicare curent în care este accesat un nume, apoi urcă în ierarhie până când se găsește o potrivire. De exemplu, dacă se caută some_local în outer_function și inner_function începe de la funcția respectivă – și găsește imediat some_local definită în outer_function și inner_function, , respectiv Atunci când un nume nu este local, acesta este preluat din cel mai apropiat domeniu de cuprindere care îl definește – căutând some_closure și print în interiorul inner_function caută până când outer_function și, respectiv, builtins.


Declarații de domeniu și legarea numelor

În mod implicit, un nume aparține oricărui domeniu de aplicare în care este legat de o valoare. Legarea din nou a aceluiași nume într-un domeniu interior creează o nouă variabilă cu același nume – de exemplu, some_local există separat atât în outer_function și inner_function. În ceea ce privește domeniul de cuprindere, legarea include orice instrucțiune care stabilește valoarea unui nume – instrucțiuni de atribuire, dar și variabila de iterație a unui for sau numele unei bucle with manager de context. În special, del se consideră, de asemenea, ca fiind o legare de nume.

Atunci când un nume trebuie să se refere la o variabilă exterioară și să fie legată într-o sferă interioară, numele trebuie să fie declarat ca nefiind local. Există declarații separate pentru diferitele tipuri de domenii de cuprindere: nonlocal se referă întotdeauna la cea mai apropiată închidere, iar global se referă întotdeauna la un nume global. În special, nonlocal nu se referă niciodată la un nume global, iar global ignoră toate închiderile cu același nume. Nu există nicio declarație care să se refere la domeniul de cuprindere construit.


some_global = "1"

def outer_function():
    some_closure = "3.2"
    some_global = "this is ignored by a nested global declaration"
    
    def inner_function():
        global some_global     # declare variable from global scope
        nonlocal some_closure  # declare variable from enclosing scope
        message = " bound by an inner scope"
        some_global = some_global + message
        some_closure = some_closure + message
    return inner_function

Este de remarcat faptul că funcțiile locale și nonlocal sunt rezolvate în momentul compilării. A nonlocal nume trebuie să fie să existe într-un domeniu exterior. În schimb, un nume global nume poate fi definit în mod dinamic și poate fi adăugat sau eliminat din domeniul global în orice moment.


Expresii de cuprindere și de atribuire

Regulile de cuprindere a cuprinderilor de liste, seturi și dicte și a expresiilor generatoare sunt următoarele aproape aceleași ca și în cazul funcțiilor. În mod similar, regulile de cuprindere pentru expresiile de atribuire sunt următoarele aproape aceleași ca și pentru legarea regulată a numelor.

Domeniul de cuprindere al comprehensiunilor și al expresiilor generatoare este de același tip ca și domeniul de cuprindere al funcțiilor. Toate numele legate în domeniul de aplicare, și anume variabilele de iterație, sunt locale sau de închidere pentru domeniul de aplicare al comprehensiunilor/generatoarelor și al domeniilor imbricate. Toate numele, inclusiv variabilele de iterație, sunt rezolvate cu ajutorul rezoluției de nume, așa cum se aplică în interiorul funcțiilor.

some_global = "global"

def outer_function():
    some_closure = "closure"
    return [            # new function-like scope started by comprehension
        comp_local      # names resolved using regular name resolution
        for comp_local  # iteration targets are local
        in "iterable"
        if comp_local in some_global and comp_local in some_global
    ]

Un := expresie de atribuire funcționează în cea mai apropiată funcție, clasă sau domeniu global. În special, în cazul în care ținta unei expresii de atribuire a fost declarată nonlocal sau global în domeniul de aplicare cel mai apropiat, expresia de atribuire respectă acest lucru ca o atribuire obișnuită.

print(some_global := "global")

def outer_function():
    print(some_closure := "closure")

Cu toate acestea, o expresie de atribuire în cadrul unei înțelegeri/generatoare funcționează pe cel mai apropiat domeniu de aplicare. domeniul de cuprindere mai apropiat al comprehensiunii/generatorului, nu domeniul de cuprindere al comprehensiunii/generatorului în sine. În cazul în care mai multe comprehensiuni/generatoare sunt imbricate, se utilizează cea mai apropiată funcție sau domeniul de aplicare global. Deoarece domeniul de cuprindere/generator poate citi închideri și variabile globale, variabila de atribuire poate fi citită și în cadrul înțelegerii. Nu este valabilă atribuirea de la o comprehensiune la o clasă.

print(some_global := "global")

def outer_function():
    print(some_closure := "closure")
    steps = [
        # v write to variable in containing scope
        (some_closure := some_closure + comp_local)
        #                 ^ read from variable in containing scope
        for comp_local in some_global
    ]
    return some_closure, steps

În timp ce variabila de iterație este locală pentru înțelegerea în care este legată, ținta expresiei de atribuire nu creează o variabilă locală și este citită din domeniul de cuprindere exterior:

┎ builtins           [print, ...]
┗━┱ globals            [some_global]
  ┗━┱ outer_function     [some_closure]
    ┗━╾ <listcomp>         [comp_local]

GraceMeng

În Python,

orice variabilă căreia i se atribuie o valoare este locală pentru blocul în care apare atribuirea.

Dacă o variabilă nu poate fi găsită în domeniul de aplicare curent, vă rugăm să vă referiți la ordinea LEGB.