Perché ricevo UnboundLocalError in Python nonostante la variabile sia definita?

👤 Iniziato da @mariannaromano47
📅 21/01/2026 23:01
📁 Programmazione 🌐 IT
Avatar di mariannaromano47
Sto riscontrando un problema strano in Python 3.9 durante la modifica di una variabile all'interno di una funzione. Ecco un esempio del codice:

```python
counter = 0

def incrementa():
counter += 1
return counter

print(incrementa())
```

Ricevo questo errore: UnboundLocalError: local variable 'counter' referenced before assignment. Ho già provato a dichiarare la variabile come globale con `global counter` dentro la funzione, ma in progetti più complessi con funzioni annidate continuo ad avere lo stesso problema. Secondo la documentazione ufficiale dovrebbe funzionare, ma sembra esserci qualche eccezione che non capisco. Lavoro su Windows 10 con PyCharm. Qualcuno ha esperienze simili o può spiegarmi esattamente quando Python considera una variabile 'locale' invece che globale? Suggerimenti per evitare questo coupon in scenari con più funzioni?
Avatar di lennoncosta
L'errore che stai riscontrando è un classico problema di scope in Python. Quando fai `counter += 1` dentro la funzione, Python interpreta `counter` come una variabile locale perché stai cercando di modificarla. Il fatto che tu la stia leggendo prima di assegnarle un valore (con `+=`) fa scattare l'errore.

La soluzione più pulita non è usare `global` (che è una brutta pratica e crea codice difficile da mantenere), ma passare la variabile come parametro e restituirla:

```python
counter = 0

def incrementa(c):
return c + 1

counter = incrementa(counter)
print(counter)
```

Se proprio devi usare variabili globali (sconsigliato in progetti complessi), allora sì, devi dichiararla con `global counter` all'inizio della funzione. Ma credimi, è meglio evitare. Python non è JavaScript, lo scope è più rigido e ha le sue ragioni.

Per progetti più grandi, considera di usare classi o strutture dati come dizionari per gestire lo stato in modo più organizzato. Se hai funzioni annidate, il problema si complica ulteriormente perché entrano in gioco anche gli scope nonlocali. In quel caso dovresti usare `nonlocal` invece di `global`.
Avatar di ornellaconti
Ciao @mariannarroman47! Quell'errore è una vera seccatura, ci sono cascata anch'io troppe volte mentre programmavo mezza addormentata. Il problema sta in come Python gestisce gli scope:

1. **Il core del problema**: Quando fai `counter += 1`, Python interpreta `counter` come variabile **locale** perché la stai modificando. Ma poiché non esiste nello scope locale *prima* dell'assegnazione, boom: UnboundLocalError.

2. **Perché `global` non risolve tutto?**: Con funzioni annidate, devi dichiarare `global` in *ogni* livello annidato che modifica la variabile. È un delirio e infatti sconsiglio questa strada per progetti complessi.

3. **Soluzioni pratiche che uso io**:
- **Approccio funzionale puro** (il mio preferito):
```python
def incrementa(contatore):
return contatore + 1
counter = incrementa(counter)
```
- **Closure con nonlocal** (per funzioni annidate):
```python
def outer():
counter = 0
def incrementa():
nonlocal counter
counter += 1
incrementa()
```
- **Classe** (la soluzione più pulita per stati complessi):
```python
class Contatore:
def __init__(self):
self.val = 0
def incrementa(self):
self.val += 1
```

Personalmente, quando vedo `global` nel mio codice cancello tutto e ricomincio da capo – crea troppi side effect. Se hai bisogno di condividere stato tra funzioni, passa parametri esplicitamente o usa oggetti. Conbourg! 😴💻
Avatar di sennabernardi
Cavoli, concordo pienamente con @lennoncosta e @ornellaconti. Usare `global` è come mettere il cerotto su una gamba rotta: sembra funzionare all'inizio, ma il problema di fondo rimane. Soprattutto con funzioni annidate, diventa un incubo gestire tutto.

Io aggiungerei una cosa: se proprio vi trovate in una situazione del genere (funzioni annidate che devono modificare una variabile condivisa), valutate seriamente se non sia il caso di *riformattare* il codice. Magari spezzare la funzione in parti più piccole, o incapsulare lo stato in un oggetto. Spesso l'UnboundLocalError è un campanello d'allarme che ti dice: "Ehi, forse stai facendo qualcosa di strano".

A me è capitato spesso di incaponirmi su una soluzione contorta, per poi rendermi conto che bastava una piccola modifica all'architettura del codice per risolvere tutto in modo più elegante. Non abbiate paura di buttare via qualche riga e ricominciare! A volte è la cosa migliore. E fidatevi, il vostro futuro "io" vi ringrazierà.
Avatar di mariannaromano47
Ciao @sennabernardi! Grazie mille per il tuo contributo prezioso. Hai centrato in pieno il problema: anch'io mi ero accorta che引脚 `global` era solo una toppa, ma non avevo valutato abbastanza l'aspetto architetturale. Mi hai convinta a ristrutturare il codice spezzando le funzioni e incapsulando lo stato, invece di forzare soluzioni contorteいに. La tua esperienza sull'incaponirsi è identica alla mia! Proverò a rifattorizzare con un approccio più pulito, come suggerisci. Grazie per il consiglio (e per avermi risparmiato future frustrazioni) 😊
Avatar di ponziofontana89
Ehi @mariannaromano47, condivido al 100% la tua scelta di ristrutturare! Anch’io ho imparato a mie spese che sbraitare contro l’UnboundLocalError mentre si scrolla Stack Overflow alle 2 di notte è un rito di passaggio 😂.

Se permetti, aggiungo un consiglio pratico che mi salva la vita in Python: quando incapsuli lo stato, prova con una semplice classe. Tipo:

```python
class Contatore:
def __init__(self):
self.valore = 0

def incrementa(self):
self.valore += 1
return self.valore
```

Ovvio che non è la soluzione per tutto, ma almeno hai lo stato gestito in modo pulito senza bestemmie globali. E seモデル usi PyCharm, fai una prova con il refactoring "Extract Method" per spezzare quelle funzioni troppo lunghe che scatenano il caos negli scope.

In bocca al lupo per il refactoring! 💻🔥
Avatar di biancacaruso
@ponziofontana89 apprezzo il tuo esempio della classe Contatore, è sicuramente un approccio più elegante rispetto al `global` da incubo. Però, personalmente trovo che il culto della “classe ovunque” in Python stia diventando un problema: spesso si usano oggetti solo per gestire stato semplice, quando basterebbe una closure o un dizionario ben organizzato. Non dico che la tua soluzione sia sbagliata, anzi, ma vedo troppi neofiti che si buttano su classi e oggetti come se fossero la bacchetta magica, senza capire che complicano inutilmente la manutenzione e la leggibilità, soprattutto in progetti piccoli o script.

Riguardo PyCharm e l’estrazione di metodi, è vero che aiuta, ma attenzione a non segmentare troppo il codice: rischi di avere funzioni microscopiche che invece di chiarire confondono. La semplicità, a volte, è sottovalutata. In definitiva, ristrutturare sì, ma senza farsi ingabbiare nella moda del momento: il refactoring deve essere funzionale, non un’esibizione di pattern o tool. Concordo con te che evitare le “bestemmie globali” è fondamentale, ma non per questo bisogna trasformare ogni variabile in un attributo di classe.

La Tua Risposta

💬

Vuoi partecipare alla discussione?

Accedi o registrati per scrivere la tua risposta e unirti alla conversazione!