Risposte:
Questo non ha nulla a che fare con Python; le variabili globali sono cattive in qualsiasi linguaggio di programmazione.
Tuttavia, le costanti globali non sono concettualmente le stesse delle variabili globali ; le costanti globali sono perfettamente innocue. In Python la distinzione tra i due è puramente convenzionale: CONSTANTS_ARE_CAPITALIZED
e globals_are_not
.
Il motivo per cui le variabili globali sono cattive è che consentono alle funzioni di avere effetti collaterali nascosti (non ovvi, sorprendenti, difficili da rilevare, difficili da diagnosticare), portando a un aumento della complessità, portando potenzialmente al codice Spaghetti .
Tuttavia, un uso sano dello stato globale è accettabile (così come lo stato locale e la mutabilità) anche nella programmazione funzionale, sia per l'ottimizzazione dell'algoritmo, la complessità ridotta, la memorizzazione nella cache e la memoizzazione, sia per la praticità delle strutture di porting originate da una base di codice prevalentemente imperativa.
Tutto sommato, è possibile rispondere alla tua domanda in molti modi, quindi la soluzione migliore è semplicemente cercare su Google "perché le variabili globali sono cattive". Qualche esempio:
Se vuoi andare più a fondo e scoprire perché sono tutti gli effetti collaterali e molte altre cose illuminanti, dovresti imparare la Programmazione Funzionale:
Sì, in teoria , i globali (e lo "stato" in generale) sono il male. In pratica, se guardi nella directory dei pacchetti del tuo python, scoprirai che la maggior parte dei moduli inizia con un mucchio di dichiarazioni globali. Ovviamente, le persone non hanno problemi con loro.
In particolare per Python, la visibilità delle globali è limitata a un modulo, quindi non ci sono globali "vere" che influenzano l'intero programma, il che le rende meno dannose. Un altro punto: non ce ne sono const
, quindi quando hai bisogno di una costante devi usare una globale.
Nella mia pratica, se mi capita di modificare un globale in una funzione, lo dichiaro sempre con global
, anche se tecnicamente non ce n'è bisogno, come in:
cache = {}
def foo(args):
global cache
cache[args] = ...
Questo rende le manipolazioni delle variabili globali più facili da rintracciare.
Un'opinione personale sull'argomento è che avere variabili globali utilizzate in una logica di funzione significa che qualche altro codice può alterare la logica e l'output atteso di quella funzione che renderà il debug molto difficile (specialmente nei grandi progetti) e renderà più difficili i test anche.
Inoltre, se consideri che altre persone leggano il tuo codice (comunità open source, colleghi ecc.), Avranno difficoltà a capire dove è stata impostata la variabile globale, dove è stata modificata e cosa aspettarsi da questa variabile globale al contrario a una funzione isolata che la sua funzionalità può essere determinata leggendo la definizione della funzione stessa.
Credo che un codice pulito e (quasi) privo di bug dovrebbe avere funzioni quanto più pure possibili (vedere funzioni pure ). Una funzione pura è quella che presenta le seguenti condizioni:
Avere variabili globali viola almeno una delle precedenti se non entrambe, poiché un codice esterno può probabilmente causare risultati imprevisti.
Un'altra chiara definizione di funzioni pure: "La funzione pura è una funzione che prende tutti i suoi input come argomenti espliciti e produce tutti i suoi output come risultati espliciti ". [1] . Avere variabili globali viola l'idea di funzioni pure poiché un input e forse uno degli output (la variabile globale) non viene esplicitamente fornito o restituito.
Più avanti che, se si considera unit test e il primo principio ( F test AST, I test ndependent, R epeatable, S elfo-Verifica e T imely) probabilmente saranno violare il principio di test indipendente (il che significa che i test non dipendono l'uno sull'altro).
Avere una variabile globale (non sempre) ma nella maggior parte dei casi (almeno di quello che ho visto finora) è preparare e passare i risultati ad altre funzioni. Ciò viola anche questo principio. Se la variabile globale è stata usata in quel modo (cioè la variabile globale usata nella funzione X deve essere prima impostata in una funzione Y) significa che per unit test della funzione X devi prima eseguire test / eseguire la funzione Y prima.
D'altra parte e come altre persone hanno già detto, se la variabile globale viene utilizzata come variabile "costante" può essere leggermente migliore poiché il linguaggio non supporta le costanti. Tuttavia, preferisco sempre lavorare con le classi e avere le "costanti" come membro della classe e non utilizzare affatto una variabile globale. Se si dispone di un codice che due classi diverse richiedono per condividere una variabile globale, è probabile che sia necessario rifattorizzare la soluzione e rendere le classi indipendenti.
Non credo che le globali non dovrebbero essere usate. Ma se vengono utilizzati, gli autori dovrebbero considerare alcuni principi (quelli menzionati sopra forse e altri principi e buone pratiche di ingegneria del software) per un codice più pulito e quasi privo di bug.
Sono essenziali, lo schermo è un buon esempio. Tuttavia, in un ambiente multithread o con molti sviluppatori coinvolti, in pratica spesso sorge la domanda: chi lo ha (erroneamente) impostato o cancellato? A seconda dell'architettura, l'analisi può essere costosa ed essere richiesta spesso. Mentre leggere la var globale può essere ok, la scrittura su di essa deve essere controllata, ad esempio da un singolo thread o da una classe threadsafe. Quindi, le variabili globali fanno sorgere il timore degli alti costi di sviluppo possibili dalle conseguenze per le quali sono considerati negativi. Pertanto, in generale, è buona norma mantenere basso il numero di variabili globali.
eval
,import *
, concatenazione di stringhe , variabiliid
, le ombre degli attributi )