Ajout de code à __init__.py
-
02-07-2019 - |
Question
Je regarde comment fonctionne le système modèle de Django et j'ai remarqué quelque chose que je ne comprends pas.
Je sais que vous créez un fichier __ init __. py
vide pour spécifier que le répertoire en cours est un package. Et que vous pouvez définir une variable dans __ init __. Py
afin que l'importation * fonctionne correctement.
Mais django ajoute une série d’instructions ... importées et définit une série de classes dans __ init __. py
. Pourquoi? Est-ce que cela ne rend pas les choses plus difficiles? Existe-t-il une raison pour laquelle ce code est requis dans __ init __. Py
?
La solution
Toutes les importations dans __ init __. py
sont rendues disponibles lorsque vous importez le package (répertoire) qui le contient.
Exemple:
./ dir / __ init __. py
:
import something
./ test.py
:
import dir
# can now use dir.something
EDIT: oublié de mentionner, le code dans __ init __. py
est exécuté lors de la première importation d’un module à partir de ce répertoire. C'est donc normalement un bon endroit pour mettre n'importe quel code d'initialisation au niveau du paquet.
EDIT2: dgrant a signalé une confusion possible dans mon exemple. Dans __ init __. Py
, quelque chose
peut importer n'importe quel module, ce qui n'est pas nécessaire depuis le package. Par exemple, nous pouvons le remplacer par import datetime
, puis dans notre niveau supérieur test.py
, ces deux extraits fonctionneront:
import dir
print dir.datetime.datetime.now()
et
import dir.some_module_in_dir
print dir.datetime.datetime.now()
La ligne du bas est la suivante: tous les noms attribués dans __ init __. py
, qu’il s’agisse de modules, fonctions ou classes importés, sont automatiquement disponibles dans l’espace de noms du package lorsque vous importez le package ou un module dans le package. .
Autres conseils
Il s’agit vraiment de préférences personnelles et de la disposition de vos modules python.
Supposons que vous ayez un module appelé erikutils
. Cela peut être un module de deux manières: soit vous avez un fichier nommé erikutils.py sur votre sys.path
, soit un répertoire appelé erikutils sur votre sys.path
avec un fichier __ init __. py
vide. Ensuite, supposons que vous disposiez de plusieurs modules appelés fileutils
, procutils
, parseutils
et que vous souhaitiez que ceux-ci soient des sous-modules sous erikutils
. Vous créez donc des fichiers .py nommés fileutils.py , procutils.py et parseutils.py :
erikutils
__init__.py
fileutils.py
procutils.py
parseutils.py
Vous avez peut-être quelques fonctions qui n'appartiennent tout simplement pas aux modules fileutils
, procutils
ou parseutils
. Et disons que vous n'avez pas envie de créer un nouveau module appelé miscutils
. ET vous voudriez pouvoir appeler la fonction comme suit:
erikutils.foo()
erikutils.bar()
plutôt que de faire
erikutils.miscutils.foo()
erikutils.miscutils.bar()
Comme le module erikutils
est un répertoire et non un fichier, nous devons définir ses fonctions dans le fichier __ init __. py
.
Dans Django, le meilleur exemple que je puisse penser est django.db.models.fields
. TOUTES les classes de champs django * sont définies dans le fichier __ init __. Py
du répertoire django / db / models / fields . Je suppose qu’ils ont fait cela parce qu’ils ne voulaient pas tout mettre dans un modèle hypothétique django / db / models / fields.py , ils l’ont donc divisé en quelques sous-modules (liés à . py , fichiers.py , par exemple) et ils ont collé les définitions de * champs définies dans le module de champs lui-même (d'où: __ init __. py
).
L'utilisation du fichier __ init __. py
vous permet de rendre la structure de package interne invisible de l'extérieur. Si la structure interne change (par exemple, parce que vous avez scindé un module fat en deux), vous devez uniquement ajuster le fichier __ init __. Py
, mais pas le code qui dépend du package. Vous pouvez également rendre certaines parties de votre package invisibles, par exemple. s'ils ne sont pas prêts pour un usage général.
Notez que vous pouvez utiliser la commande del
. Ainsi, un __ init __. py
typique peut ressembler à ceci:
from somemodule import some_function1, some_function2, SomeObject
del somemodule
Maintenant, si vous décidez de scinder un module
, le nouveau __ init __. py
pourrait être:
from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject
del somemodule1
del somemodule2
De l'extérieur, le paquet a toujours l'apparence exacte.