Posso usare __init__.py per definire le variabili globali?


130

Voglio definire una costante che dovrebbe essere disponibile in tutti i sottomoduli di un pacchetto. Ho pensato che il posto migliore sarebbe nel __init__.pyfile del pacchetto root. Ma non so come farlo. Supponiamo che io abbia alcuni subpackages e ognuno con diversi moduli. Come posso accedere a quella variabile da questi moduli?

Certo, se questo è totalmente sbagliato e c'è un'alternativa migliore, mi piacerebbe saperlo.

Risposte:


196

Dovresti essere in grado di inserirli __init__.py. Questo è fatto tutto il tempo.

mypackage/__init__.py:

MY_CONSTANT = 42

mypackage/mymodule.py:

from mypackage import MY_CONSTANT
print "my constant is", MY_CONSTANT

Quindi, importa mymodule:

>>> from mypackage import mymodule
my constant is 42

Tuttavia, se si dispone di costanti, sarebbe ragionevole (best practice, probabilmente) metterle in un modulo separato (constants.py, config.py, ...) e quindi se le si desidera nello spazio dei nomi del pacchetto, importare loro.

mypackage/__init__.py:

from mypackage.constants import *

Tuttavia, ciò non include automaticamente le costanti negli spazi dei nomi dei moduli del pacchetto. Ciascuno dei moduli nel pacchetto dovrà comunque importare in modo esplicito costanti da mypackageo da mypackage.constants.


19
Questa avrebbe dovuto essere la risposta accettata. Se stai lavorando con Python 2.5 o versioni successive puoi anche utilizzare un'importazione relativa esplicita e descritta qui : from . import MY_CONSTANT
ThatAintWorking,

il secondo modo non funziona solo per le costanti? from mypackage.constants import *inserirà copie di MY_CONSTANTogni sottomodulo piuttosto che un riferimento alla stessa variabile
liscio

@hardmooth: non esattamente. I valori vengono copiati per riferimento, quindi se dovessi mutare MY_CONSTANTin uno qualsiasi dei moduli, muterebbe ovunque. Se dovessi riassegnare MY_CONSTANTuno dei moduli, ciò influirebbe solo su quel modulo. Se questa è la tua intenzione, devi fare riferimento per attributo, ad es mypackage.constants.MY_CONSTANT.
Jason R. Coombs,

7
Una cattura con l'esempio è se si importa mymodule.pyin __init__.pyprima MY_CONSTANT = 42che fallirà perché quando l'importazione mymodule.py MY_CONSTANTnon è stato ancora definito. Quindi è necessario spostarsi MY_CONSTANT = 42sopraimport mymodule
markmnl

che ne dici di variabile? Si tratta di variabili, non di costanti. Come Python tratta le variabili all'interno del pacchetto? Cosa succede se la variabile all'interno del pacchetto è stata modificata?
TomSawyer,

31

Non puoi farlo. Dovrai importare esplicitamente le tue costanti nello spazio dei nomi di ogni singolo modulo. Il modo migliore per raggiungere questo obiettivo è definire le costanti in un modulo "config" e importarlo ovunque sia necessario:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *

Sì, un file di configurazione è quello che vorrei. Ho solo pensato che init .py sarebbe stato un buon posto. La tua soluzione sembra una pratica standard. È?
Andrei Vajna II,

1
Buon punto. Non mi ero reso conto che la domanda fosse che le costanti fossero automaticamente collocate nello spazio dei nomi di tutti i moduli del pacchetto.
Jason R. Coombs,

Ma ogni volta che uno script importa config.py, il codice all'interno viene eseguito. Cosa mi consigliate se il codice all'interno di config.py deve essere eseguito una sola volta? Supponiamo che sto leggendo un file settings.json all'interno di config.py e non voglio aprirlo () ogni volta che importa config.py.
Augiwan,

@UGS Non funziona così Python. Ogni modulo viene eseguito una sola volta. Quando viene importato la seconda volta, il modulo è già memorizzato nella cache sys.modules.
Ferdinand Beyer,

@FerdinandBeyer Oops! Ho dimenticato di menzionare che sto importando config.py da diversi script e non dallo stesso script. Supponiamo che a.py stia importando config.py & b.py e b.py stia importando config.py. Mi chiedevo se fosse possibile assicurarsi che il codice all'interno di config.py fosse eseguito una sola volta.
Augiwan,

2

Puoi definire variabili globali da qualsiasi luogo, ma è una pessima idea. importare il __builtin__modulo e modificare o aggiungere attributi a questi moduli e improvvisamente si hanno nuove costanti o funzioni incorporate. In effetti, quando la mia applicazione installa gettext, ottengo la funzione _ () in tutti i miei moduli, senza importare nulla. Quindi questo è possibile, ma ovviamente solo per progetti di tipo Application, non per pacchetti o moduli riutilizzabili.

E suppongo che nessuno raccomanderebbe comunque questa pratica. Cosa c'è di sbagliato in uno spazio dei nomi? Detta applicazione ha il modulo versione, quindi ho variabili "globali" disponibili come version.VERSION, version.PACKAGE_NAMEecc.


0

Volevo solo aggiungere che le costanti possono essere impiegate usando un file config.ini e analizzate nello script usando la libreria configparser. In questo modo potresti avere costanti per più circostanze. Ad esempio, se avessi costanti di parametri per due richieste url separate, etichettale in questo modo:

mymodule/config.ini
[request0]
conn = 'admin@localhost'
pass = 'admin'
...

[request1]
conn = 'barney@localhost'
pass = 'dinosaur'
...

Ho trovato molto utile la documentazione sul sito Web di Python. Non sono sicuro se ci sono differenze tra Python 2 e 3, quindi ecco i collegamenti ad entrambi:

Per Python 3: https://docs.python.org/3/library/configparser.html#module-configparser

Per Python 2: https://docs.python.org/2/library/configparser.html#module-configparser

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.