17 settembre, 2019
Visibilità (scope) delle variabili - 1
Continuo da qui la serie di post elementari sui linguaggi con visibilità delle variabili lessicale e/o dinamica. Però ormai parlo di un argomento collegato, più personale, probabilmente interessa solo me.
Ah! una cosa in parte OT: mi sono letto i documenti citati in bibliografia da Ming-Ho (non tutti, confesso), avendo tempo ci sono cose interessanti, qualcuna la sapevo, altre meno. Ma il solito problema: il tempo.
Questo post arriva in cascata alla serie ma è diverso, forse sono solo io che ho fatto confusione, voglio chiarirmi un po' meglio come Python e JavaScript considerano le variabili, globali e locali. Un post molto semplice, didascalico, solo per me (probabilmente, come già detto).
Normalmente le variabili (numeriche, vedremo prossimamente che per gli oggetti valgono altre leggi) sono passate come valore alle funzioni e nel chiamante il loro valore non muta. Esempio, in Python:
def f():
print('f()', x)
return x
def g(n):
x = n
print('g()', n, f())
return f()
# main
x = 1
print('start x =', x)
print(x, f(), g(2), x, f())
x = 5
print('cambio x =', x)
print(x, f(), g(3), x, f())
$ py3 s-n.py
start x = 1
f() 1
f() 1
g() 2 1
f() 1
f() 1
1 1 1 1 1
cambio x = 5
f() 5
f() 5
g() 3 5
f() 5
f() 5
5 5 5 5 5
$
Stesso comportamento con JavaScript con l'avvertenza di definite con var le variabili locali, altrimenti sono globali:
function f() {
console.log('f()', x)
return x
}
function g(n) {
var x = n
console.log('g()', n, f())
return f()
}
// main
x = 1
console.log('start x =', x)
console.log(x, f(), g(2), x, f())
x = 5
console.log('cambio x =', x)
console.log(x, f(), g(3), x, f())
$ node s-n.js
start x = 1
f() 1
f() 1
g() 2 1
f() 1
f() 1
1 1 1 1 1
cambio x = 5
f() 5
f() 5
g() 3 5
f() 5
f() 5
5 5 5 5 5
$
OK, finora tutte le variabili sono locali (in realtà c'è la sola x in g()); Per operare con variabili globali in Python uso l'instruzione global globalmente, cioè esterna alle funzioni. Ma in questo caso il comportamento è diverso da come potrebbe apparire (è un errore!): la x in g() è locale:
global x
def f():
print('f()', x)
return x
def g(n):
x = n
print('g()', n, f())
return f()
# main
x = 1
print('start x =', x)
print(x, f(), g(2), x, f())
x = 5
print('cambio x =', x)
print(x, f(), g(3), x, f())
$ py3 s-ge.py
start x = 1
f() 1
f() 1
g() 2 1
f() 1
f() 1
1 1 1 1 1
cambio x = 5
f() 5
f() 5
g() 3 5
f() 5
f() 5
5 5 5 5 5
$
Risulta che il valore di x in g() non ha influenza su f() perché questa è globale e non relativa a g().
Per chiarire uno script ancora più focalizzato
global x
x = 1
def g(n):
print(x) # <- errore qui, x non è definita
x = n
print(x)
#main
g(2)
print(x)
eseguendola si ottiene un errore:
$ py3 gl.py
Traceback (most recent call last):
File "gl.py", line 10, in <module>
g(2)
File "gl.py", line 5, in g
print(x)
UnboundLocalError: local variable 'x' referenced before assignment
$
commentando la print iniziale in g() risulta come in g() x sia locale:
$ py3 gl.py
2
1
$
In JavaScript, dove le variabili sono globali di default:
function f() {
console.log('f()', x)
return x
}
function g(n) {
x = n // modif qui, x è globale
console.log('g()', n, f())
return f()
}
// main
x = 1
console.log('start x =', x)
console.log(x, f(), g(2), x, f())
x = 5
console.log('cambio x =', x)
console.log(x, f(), g(3), x, f())
$ node s-ge.js
start x = 1
f() 1
f() 2
g() 2 2
f() 2
f() 2
1 1 2 2 2
cambio x = 5
f() 5
f() 3
g() 3 3
f() 3
f() 3
5 5 3 3 3
$
OOPS! in questo caso la x in g() determina il valore di f(). Ho cioè un comportamento diverso per i due linguaggi, cosa che almeno per me induce errori se non si presta la dovuta attenzione. (Sì, sono ripetitivo).
Da sempre si usano variabili globali ma per quanto è possibile queste vanno limitate per quanto possibile. La variabile x in g() che voglio globale la dichiaro global all'interno della funzione; la chiamata a g() sarà diversa a quella ad h() dove x è locale. Peraltro diventa importante l'ordine delle chiamate:
def f():
print('f()', x)
return x
def g(n):
global x
x = n
print('g()', n, f())
return f()
def h(n):
x = n
print('h()', n, f())
return f()
# main
x = 1
print('start x =', x)
print(x, f(), g(2), x, f())
x = 5
print('cambio x =', x)
print(x, f(), g(3), x, f())
x = 8
print('cambio x =', x)
print(x, f(), h(4), g(3), x, h(6), f())
$ py3 s-gl.py
start x = 1
f() 1
f() 2
g() 2 2
f() 2
f() 2
1 1 2 2 2
cambio x = 5
f() 5
f() 3
g() 3 3
f() 3
f() 3
5 5 3 3 3
cambio x = 8
f() 8
f() 8
h() 4 8
f() 8
f() 3
g() 3 3
f() 3
f() 3
h() 6 3
f() 3
f() 3
8 8 8 3 3 3 3
$
JavaScript, per quanto precedentemente detto è in questo caso più intuitivo
function f() {
console.log('f()', x)
return x
}
function g(n) {
x = n // modif qui, x è globale
console.log('g()', n, f())
return f()
}
function h(n) {
var x = n // x è locale
console.log('h()', n, f())
return f()
}
// main
x = 1
console.log('start x =', x)
console.log(x, f(), g(2), x, f())
x = 5
console.log('cambio x =', x)
console.log(x, f(), g(3), x, f())
x = 8
console.log('cambio x =', x)
console.log(x, f(), h(4), g(3), x, h(6), f())
$ node s-gl.js
start x = 1
f() 1
f() 2
g() 2 2
f() 2
f() 2
1 1 2 2 2
cambio x = 5
f() 5
f() 3
g() 3 3
f() 3
f() 3
5 5 3 3 3
cambio x = 8
f() 8
f() 8
h() 4 8
f() 8
f() 3
g() 3 3
f() 3
f() 3
h() 6 3
f() 3
f() 3
8 8 8 3 3 3 3
$
OK, ma le liste? Uh! per le liste (gli oggetti) questo non vale, come vedremo prossimament, non cambiate canale 🙂
🔴
Iscriviti a:
Commenti sul post (Atom)
Nessun commento:
Posta un commento