Usando le variabili globali tra i file?


209

Sono un po 'confuso su come funzionano le variabili globali. Ho un grande progetto, con circa 50 file e ho bisogno di definire variabili globali per tutti quei file.

Quello che ho fatto è stato definirli nel mio main.pyfile di progetti , come segue:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

Sto cercando di utilizzare myListin subfile.py, come segue

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
    globals()["myList"].append("hey")

In un altro modo ho provato, ma non ha funzionato neanche

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

E dentro subfile.pyho avuto questo:

# ../myproject/subfile.py

# Import globfile
import globfile

# Save "hey" into myList
def stuff():
    globfile.myList.append("hey")

Ma ancora una volta, non ha funzionato. Come dovrei implementarlo? Capisco che non può funzionare in questo modo, quando i due file non si conoscono davvero bene (bene il file secondario non conosce main), ma non riesco a pensare a come farlo, senza usare io writing o pickle, che Non voglio fare


In realtà, il tuo secondo approccio funziona bene per me. main.py stampa correttamente "hey". Puoi essere più specifico su quello che mi dai "non ha funzionato"?
rodione,

@rodion: cicli di importazione - il codice nel sottofile tenta di importare globfile, che nel suo corpo reimporta se stesso
jsbueno,

1
NameError: name 'myList' is not defineddalla main.pylineaprint(globfile.myList[0])

Risposte:


321

Il problema è definito myListda main.py, ma è subfile.pynecessario utilizzarlo. Ecco un modo chiaro per risolvere questo problema: sposta tutti i globuli in un file, chiamo questo file settings.py. Questo file è responsabile della definizione e dell'inizializzazione dei globi:

# settings.py

def init():
    global myList
    myList = []

Successivamente, subfilepuoi importare globalmente:

# subfile.py

import settings

def stuff():
    settings.myList.append('hey')

Nota che subfilenon chiama init(): quell'attività appartiene a main.py:

# main.py

import settings
import subfile

settings.init()          # Call only once
subfile.stuff()         # Do stuff with global var
print settings.myList[0] # Check the result

In questo modo, raggiungi il tuo obiettivo evitando di inizializzare le variabili globali più di una volta.


41
Mi piace l'approccio generale, ma non tutto il init()resto. I moduli vengono valutati solo la prima volta che vengono importati, quindi è perfettamente OK inizializzare quelle variabili nel corpo del modulo.
Kirk Strauser,

19
+1 Kirk: sono d'accordo. Tuttavia, il mio approccio impedisce il caso in cui altri moduli modificano globals.myList prima dell'avvio del programma principale.
Hai Vu,

2
Dovresti chiamarlo qualcosa di diverso dai globali, che è un nome predefinito. PyLint dà l'avvertimento: "Ridefinire i 'globals' incorporati (ridefinito-builtin)"
twasbrillig,

Grazie. Qualche idea su come rimuovere gli errori "Variabile non definita dall'importazione" che compaiono in Eclipse PyDev usando questa struttura di file (ovvero importando variabili globali da settings.py)? Ho dovuto disabilitare l'errore in PyDev , che non è l'ideale.
Franck Dernoncourt,

@FranckDernoncourt Mi dispiace, non uso Eclipse quindi sono ancora più all'oscuro di te.
Hai Vu,

94

Vedi il documento di Python sulla condivisione delle variabili globali tra i moduli :

Il modo canonico di condividere informazioni tra i moduli all'interno di un singolo programma è quello di creare un modulo speciale (spesso chiamato config o cfg).

config.py:

x = 0   # Default value of the 'x' configuration setting

Importa il modulo di configurazione in tutti i moduli dell'applicazione; il modulo diventa quindi disponibile come nome globale.

main.py:

import config
print (config.x)

o

from config import x
print (x)

In generale, non utilizzare da modulename import * . In questo modo si ingombra lo spazio dei nomi dell'importatore e si rende molto più difficile per i linter rilevare i nomi indefiniti.


1
Salvagente - solo per quel link!
toonarmycaptain

4
Questo sembra un approccio più pulito rispetto alla risposta accettata.
JoeyC

2
Nota che non puoi impostare xusando from config import x, solo usandoimport config
Yariv

1
La soluzione più semplice! Grazie
user1297406

22

Puoi pensare alle variabili globali di Python come variabili "modulo" - e come tali sono molto più utili delle tradizionali "variabili globali" di C.

Una variabile globale è effettivamente definita in un modulo __dict__ ed è possibile accedervi dall'esterno di quel modulo come attributo del modulo.

Quindi, nel tuo esempio:

# ../myproject/main.py

# Define global myList
# global myList  - there is no "global" declaration at module level. Just inside
# function and methods
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

E:

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
     # You have to make the module main available for the 
     # code here.
     # Placing the import inside the function body will
     # usually avoid import cycles - 
     # unless you happen to call this function from 
     # either main or subfile's body (i.e. not from inside a function or method)
     import main
     main.mylist.append("hey")

1
wow, normalmente ci si aspetterebbe che due file che si importano a vicenda entrino in un ciclo infinito.
Nikhil VJ,

2
a prima vista sembra così, no? Quello che succede nella def stuff () è che l'importazione non viene eseguita quando il file viene caricato .. viene eseguita solo quando viene chiamata la funzione stuff (). Quindi a partire da main importiamo il file secondario e quindi chiamiamo subfile.stuff () che quindi importa main ... no loop, importa solo una volta in main. Vedi la nota nell'esempio subfile.py sui cicli di importazione.
John,

11

L'uso from your_file import *dovrebbe risolvere i tuoi problemi. Definisce tutto in modo che sia disponibile a livello globale (ad eccezione delle variabili locali nelle importazioni ovviamente).

per esempio:

##test.py:

from pytest import *

print hello_world

e:

##pytest.py

hello_world="hello world!"

4
Tranne se si assegna a una di queste variabili
jsbueno,

5
Evito personalmente l'uso import *a tutti i costi in modo che i riferimenti siano espliciti (e non confusi). Inoltre, quando mai hai mai usato tutti i *riferimenti " " in qualsiasi modulo?
ThorSummoner,

19
NON importare *. Le variabili globali non rimarranno più sincronizzate. Ogni modulo riceve la propria copia. La modifica della variabile in un file non si rifletterà in un altro. È anche messo in guardia da docs.python.org/2/faq/…
Isa Hassen,

8

La risposta di Hai Vu funziona alla grande, solo un commento:

Nel caso in cui si utilizzi il globale in un altro modulo e si desideri impostare il globale in modo dinamico, prestare attenzione a importare gli altri moduli dopo aver impostato le variabili globali, ad esempio:

# settings.py
def init(arg):
    global myList
    myList = []
    mylist.append(arg)


# subfile.py
import settings

def print():
    settings.myList[0]


# main.py
import settings
settings.init("1st")     # global init before used in other imported modules
                         # Or else they will be undefined

import subfile    
subfile.print()          # global usage

4

Il tuo secondo tentativo funzionerà perfettamente ed è in realtà un ottimo modo per gestire i nomi delle variabili che vuoi avere disponibili a livello globale. Ma hai un errore di nome nell'ultima riga. Ecco come dovrebbe essere:

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

Vedi l'ultima riga? myList è un attr di globfile, non un file secondario. Funzionerà come vuoi tu.

Mike

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.