LEGB
Criterio con il quale l’interprete cerca una variabile in un determinato namespace. Local → Enclosing → Global →Built-in
Il lookup di un riferimento avviene prima nel namespace locale (all’interno della funzione corrente), se non c’è si va a cercare nel namespace della funzione che ha chiamato la funzione corrente, ovvero il namespace enclosing. Se ancora non si è trovato nulla, si va a cercare nel namespace globale, ed infine nel namespace built-in.
Bypass di LEGB
Si può in parte bypassare questo comportamento utilizzando le keywords nonlocal e global.
def A():
global x # Si riferisce alla variabile definita a riga 12
def B():
global x # Si riferisce alla variabile definita a riga 12
nonlocal y # Si riferisce alla variabile definita a riga 8
x = 2 # Senza la definizione di riga 4 creerebbe una nuova variabile
y = 3 # Senza la definizione di riga 5 creerebbe una nuova variabile
y = 2
print("Riga 9:",x,y)
B()
print("Riga 11:",x,y)
x = 1 # riga 12
y = 1
print("Riga 14:",x,y)
A()
print("Riga 16:",x,y)Esempi di stranezze
class foo:
s = 0 # Assegnamento necessario perche l'attributo sia "definito"
def get():
return s
def somma(x,y):
s = x+y
f = foo()Se si prova a leggere l’attributo s da fuori, non c’è nessun problema f.s restituisce 0.
Quando si prova a chiamare il metodo f.foo(), però, si riceve un errore (get() takes 0 positional arguments but 1 was given). L’attributo s non sembra essere visibile.
Si prova a modificare la funzione get() in questo modo, basandosi sul messaggio di errore:
def get(self):
return sAnche in questo caso, chiamando f.get() si riceve un errore (name 's' is not defined). Ancora non si riesce a leggere l’attributo.
s non viene trovato perché python lo cerca utilizzando LEGB, ovvero dovunque tranne che a livello di oggetto. Se l’attributo non è quindi qualificato, non viene trovato.
Se l’attributo viene qualificato (oggetto.attributo), allora la ricerca avviene in due parti:
oggettoviene cercato tramite LEGB- una volta trovato oggetto, si inizia a cercare l’attributo in esso, ovviamente utilizzando la catena ereditaria via MRO
Ricerca l’attributo in
oggetto. Se è una classe cerca direttamente nelle superclassi dioggetto. Se non è una classe postoT = type(oggetto), cerca inTe poi casomai nelle superclassi sempre ordinate tramite MRO.
Si potrebbe sostituire s con return foo.s, utilizzando l’attributo “statico” della classe, ma, appunto, utilizza lo stesso dato in tutte le istanze, cosa rischiosa.