Kann ich __init__.py verwenden, um globale Variablen zu definieren?

130

Ich möchte eine Konstante definieren, die in allen Submodulen eines Pakets verfügbar sein soll. Ich habe gedacht, dass der beste Platz in der __init__.pyDatei des Root-Pakets wäre. Aber ich weiß nicht, wie ich das machen soll. Angenommen, ich habe ein paar Unterpakete mit jeweils mehreren Modulen. Wie kann ich von diesen Modulen aus auf diese Variable zugreifen?

Natürlich, wenn dies völlig falsch ist und es eine bessere Alternative gibt, würde ich es gerne wissen.

Andrei Vajna II
quelle

Antworten:

196

Sie sollten in der Lage sein, sie einzulegen __init__.py. Dies geschieht ständig.

mypackage/__init__.py::

MY_CONSTANT = 42

mypackage/mymodule.py::

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

Importieren Sie dann mymodule:

>>> from mypackage import mymodule
my constant is 42

Wenn Sie jedoch Konstanten haben, ist es sinnvoll (Best Practices, wahrscheinlich), diese in ein separates Modul (constants.py, config.py, ...) zu stellen und sie dann im Paket-Namespace zu importieren Sie.

mypackage/__init__.py::

from mypackage.constants import *

Dies schließt die Konstanten jedoch nicht automatisch in die Namespaces der Paketmodule ein. Jedes der Module im Paket muss weiterhin explizit Konstanten entweder von mypackageoder von importieren mypackage.constants.

Jason R. Coombs
quelle
19
Dies sollte die akzeptierte Antwort gewesen sein. Wenn Sie mit Python 2.5 oder höher arbeiten, können Sie auch einen expliziten relativen Import verwenden, wie hier beschrieben : from . import MY_CONSTANT
ThatAintWorking
funktioniert der zweite Weg nicht nur für Konstanten? from mypackage.constants import *wird Kopien von MY_CONSTANTin jedem Submodul platzieren und nicht als Verweis auf dieselbe Variable
hardmooth
@hardmooth: Nicht genau. Die Werte werden als Referenz kopiert. Wenn Sie also MY_CONSTANTin einem der Module mutieren, mutiert es überall. Wenn Sie MY_CONSTANTeines der Module neu zuweisen , wirkt sich dies nur auf dieses Modul aus. Wenn dies Ihre Absicht ist, müssen Sie nach Attributen referenzieren, dh mypackage.constants.MY_CONSTANT.
Jason R. Coombs
7
Ein Fang mit dem Beispiel ist , wenn Sie importieren mymodule.pyin , __init__.pybevor MY_CONSTANT = 42das wird da nicht beim Import mymodule.py MY_CONSTANTnoch nicht definiert worden. Also muss man sich nach MY_CONSTANT = 42oben bewegenimport mymodule
markmnl
Wie ist es mit Variablen? Es geht um Variablen, nicht um Konstanten. Wie behandelt Python Variablen im Paket? Was passiert, wenn die Variable im Paket geändert wurde?
TomSawyer
31

Das kannst du nicht tun. Sie müssen Ihre Konstanten explizit in den Namespace jedes einzelnen Moduls importieren. Der beste Weg, dies zu erreichen, besteht darin, Ihre Konstanten in einem "Konfigurations" -Modul zu definieren und sie überall dort zu importieren, wo Sie sie benötigen:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *
Ferdinand Beyer
quelle
Ja, eine Konfigurationsdatei ist das, was ich möchte. Ich dachte nur, dass init .py ein guter Ort wäre. Ihre Lösung klingt nach Standardpraxis. Ist es?
Andrei Vajna II
1
Guter Punkt. Mir war nicht klar, dass die Frage darin bestand, die Konstanten automatisch in den Namespace aller Paketmodule zu setzen.
Jason R. Coombs
Aber jedes Mal, wenn ein Skript config.py importiert, wird der darin enthaltene Code ausgeführt. Was empfehlen Sie, wenn der Code in config.py nur einmal ausgeführt werden soll? Angenommen, ich lese eine settings.json-Datei in config.py und möchte sie nicht jedes Mal öffnen (), wenn ich config.py importiere.
Augiwan
@UGS So funktioniert Python nicht. Jedes Modul wird nur einmal ausgeführt. Beim zweiten Import wird das Modul bereits zwischengespeichert sys.modules.
Ferdinand Beyer
@FerdinandBeyer Ups! Ich habe vergessen zu erwähnen, dass ich config.py aus mehreren Skripten und nicht aus demselben Skript importiere. Angenommen, a.py importiert config.py & b.py und b.py importiert config.py. Ich habe mich gefragt, ob es möglich ist, sicherzustellen, dass Code in config.py nur einmal ausgeführt wird.
Augiwan
2

Sie können globale Variablen von überall aus definieren, aber das ist eine wirklich schlechte Idee. Importieren Sie das __builtin__Modul und ändern oder fügen Sie Attribute zu diesen Modulen hinzu, und plötzlich haben Sie neue eingebaute Konstanten oder Funktionen. Wenn meine Anwendung gettext installiert, erhalte ich die Funktion _ () in allen meinen Modulen, ohne etwas zu importieren. Dies ist also möglich, aber natürlich nur für Projekte vom Typ Anwendung, nicht für wiederverwendbare Pakete oder Module.

Und ich denke, niemand würde diese Praxis sowieso empfehlen. Was ist los mit einem Namespace? Diese Anmeldung hat die Versionsmodul, so dass ich wie „global“ Variablen zur Verfügung haben version.VERSION, version.PACKAGE_NAMEusw.

u0b34a0f6ae
quelle
0

Ich wollte nur hinzufügen, dass Konstanten mithilfe einer config.ini-Datei verwendet und mithilfe der configparser-Bibliothek im Skript analysiert werden können. Auf diese Weise können Sie Konstanten für mehrere Umstände haben. Wenn Sie beispielsweise Parameterkonstanten für zwei separate URL-Anforderungen hatten, kennzeichnen Sie diese einfach wie folgt:

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

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

Ich fand die Dokumentation auf der Python-Website sehr hilfreich. Ich bin mir nicht sicher, ob es Unterschiede zwischen Python 2 und 3 gibt. Hier sind die Links zu beiden:

Für Python 3: https://docs.python.org/3/library/configparser.html#module-configparser

Für Python 2: https://docs.python.org/2/library/configparser.html#module-configparser

Dan Temkin
quelle