Puis-je utiliser __init__.py pour définir des variables globales?

130

Je souhaite définir une constante qui devrait être disponible dans tous les sous-modules d'un package. J'ai pensé que le meilleur endroit serait dans le __init__.pyfichier du paquet racine. Mais je ne sais pas comment faire ça. Supposons que j'ai quelques sous-packages et chacun avec plusieurs modules. Comment puis-je accéder à cette variable à partir de ces modules?

Bien sûr, si cela est totalement faux et qu'il existe une meilleure alternative, j'aimerais le savoir.

Andrei Vajna II
la source

Réponses:

196

Vous devriez pouvoir les insérer __init__.py. Cela se fait tout le temps.

mypackage/__init__.py:

MY_CONSTANT = 42

mypackage/mymodule.py:

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

Ensuite, importez mymodule:

>>> from mypackage import mymodule
my constant is 42

Néanmoins, si vous avez des constantes, il serait raisonnable (meilleures pratiques, probablement) de les mettre dans un module séparé (constants.py, config.py, ...) et ensuite si vous les voulez dans l'espace de noms du package, importez leur.

mypackage/__init__.py:

from mypackage.constants import *

Pourtant, cela n'inclut pas automatiquement les constantes dans les espaces de noms des modules du package. Chacun des modules du package devra toujours importer des constantes explicitement depuis mypackageou depuis mypackage.constants.

Jason R. Coombs
la source
19
Cela aurait dû être la réponse acceptée. Si vous travaillez avec Python 2.5 ou supérieur, vous pouvez également utiliser une importation relative explicite ainsi que décrite ici : from . import MY_CONSTANT
ThatAintWorking
la deuxième méthode ne fonctionne-t-elle pas uniquement pour les constantes? from mypackage.constants import *placera des copies de MY_CONSTANTdans chaque sous-module plutôt qu'une référence à la même variable
hardmooth
@hardmooth: Pas exactement. Les valeurs sont copiées par référence, donc si vous deviez muter MY_CONSTANTdans l'un des modules, il muterait partout. Si vous deviez réassigner l' MY_CONSTANTun des modules, cela n'affecterait que ce module. Si c'est votre intention, vous devez référencer par attribut, c'est-à-dire mypackage.constants.MY_CONSTANT.
Jason R. Coombs
7
Une prise avec l'exemple si vous importez mymodule.pydans __init__.pyavant MY_CONSTANT = 42que échouera parce que lorsque l' importation mymodule.py MY_CONSTANTn'a pas encore été défini. Il faut donc passer MY_CONSTANT = 42auimport mymodule
markmnl
qu'en est-il de la variable? Il pose des questions sur les variables, pas sur les constantes. Comment python traite les variables à l'intérieur du package? Et si la variable à l'intérieur du package a été modifiée?
TomSawyer
31

Tu ne peux pas faire ça. Vous devrez importer explicitement vos constantes dans l'espace de noms de chaque module individuel. La meilleure façon d'y parvenir est de définir vos constantes dans un module "config" et de l'importer partout où vous en avez besoin:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *
Ferdinand Beyer
la source
Ouais, un fichier de configuration est ce que je voudrais. Je pensais juste que init .py serait un bon endroit. Votre solution ressemble à une pratique courante. C'est ça?
Andrei Vajna II
1
Bon point. Je n'avais pas réalisé que la question était de placer automatiquement les constantes dans l'espace de noms de tous les modules du package.
Jason R. Coombs le
Mais chaque fois qu'un script importe config.py, le code qu'il contient est exécuté. Que recommandez-vous si le code à l'intérieur de config.py ne doit être exécuté qu'une seule fois? Disons que je lis un fichier settings.json dans config.py et que je ne veux pas l'ouvrir () à chaque fois que j'importe config.py.
Augiwan
@UGS Ce n'est pas ainsi que fonctionne Python. Chaque module est exécuté une seule fois. Lorsqu'il est importé pour la deuxième fois, le module est déjà mis en cache sys.modules.
Ferdinand Beyer
@FerdinandBeyer Oups! J'ai oublié de mentionner que j'importe le config.py à partir de plusieurs scripts et non du même script. Supposons que a.py importe config.py et b.py et que b.py importe config.py. Je me demandais s'il était possible de s'assurer que le code à l'intérieur de config.py n'est exécuté qu'une seule fois.
Augiwan
2

Vous pouvez définir des variables globales de n'importe où, mais c'est une très mauvaise idée. importez le __builtin__module et modifiez ou ajoutez des attributs à ces modules, et soudainement vous avez de nouvelles constantes ou fonctions intégrées. En fait, lorsque mon application installe gettext, j'obtiens la fonction _ () dans tous mes modules, sans rien importer. C'est donc possible, mais bien sûr uniquement pour les projets de type Application, pas pour les packages ou modules réutilisables.

Et je suppose que personne ne recommanderait cette pratique de toute façon. Quel est le problème avec un espace de noms? Cette application a le module de version, de sorte que j'ai des variables "globales" disponibles comme version.VERSION, version.PACKAGE_NAMEetc.

u0b34a0f6ae
la source
0

Je voulais juste ajouter que les constantes peuvent être utilisées à l'aide d'un fichier config.ini et analysées dans le script à l'aide de la bibliothèque configparser. De cette façon, vous pouvez avoir des constantes pour plusieurs circonstances. Par exemple, si vous aviez des constantes de paramètres pour deux demandes d'URL distinctes, étiquetez-les comme suit:

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

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

J'ai trouvé la documentation sur le site Web de Python très utile. Je ne suis pas sûr s'il existe des différences entre Python 2 et 3, alors voici les liens vers les deux:

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

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

Dan Temkin
la source