web-dev-qa-db-fra.com

Ajout de code à __init__.py

Je regarde comment fonctionne le système de modèles dans 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 courant est un package. Et que vous pouvez définir une variable dans __init__.py Pour que l'importation * fonctionne correctement.

Mais Django ajoute un tas d'instructions from ... import ... et définit un tas de classes dans __init__.py. Pourquoi? Cela ne fait-il pas que les choses semblent désordonnées? Y a-t-il une raison qui nécessite ce code dans __init__.py?

83
Erik

Toutes les importations en __init__.py sont 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 s'exécute la première fois que vous importez un module de ce répertoire. C'est donc normalement un bon endroit pour mettre n'importe quel code d'initialisation au niveau du package.

EDIT2: dgrant a signalé une confusion possible dans mon exemple. Dans __init__.pyimport something peut importer n'importe quel module, non nécessaire à partir du package. Par exemple, nous pouvons le remplacer par import datetime, puis dans notre niveau supérieur test.py ces deux extraits fonctionnent:

import dir
print dir.datetime.datetime.now()

et

import dir.some_module_in_dir
print dir.datetime.datetime.now()

La ligne du bas est: tous les noms attribués dans __init__.py, qu'il s'agisse de modules, de fonctions ou de classes importés, sont automatiquement disponibles dans l'espace de nom du package chaque fois que vous importez le package ou un module du package.

71

C'est juste une préférence personnelle et a à voir avec la disposition de vos modules python.

Disons que vous avez un module appelé erikutils. Il peut s'agir d'un module de deux manières, soit vous avez un fichier appelé erikutils.py sur votre sys.path ou vous avez un répertoire appelé erikutils sur votre sys.path avec un vide __init__.py fichier à l'intérieur. Supposons alors que vous ayez un tas de modules appelés fileutils, procutils, parseutils et que vous souhaitiez qu'ils soient des sous-modules sous erikutils. Vous créez donc des fichiers .py appelés fileutils.py, procutils.py, et parseutils.py:

erikutils
  __init__.py
  fileutils.py
  procutils.py
  parseutils.py

Peut-être avez-vous 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 aimeriez pouvoir appeler la fonction comme ceci:

erikutils.foo()
erikutils.bar()

plutôt que de faire

erikutils.miscutils.foo()
erikutils.miscutils.bar()

Donc, parce que le module erikutils est un répertoire, pas un fichier, nous devons définir ses fonctions à l'intérieur du __init__.py fichier.

À Django, le meilleur exemple auquel je peux penser est Django.db.models.fields. TOUS les Django * Les classes de champ sont définies dans le __init__.py fichier dans le répertoire Django/db/models/fields. Je suppose qu'ils l'ont fait parce qu'ils ne voulaient pas tout entasser dans un modèle hypothétique Django/db/models/fields.py, alors ils l'ont divisé en quelques sous-modules (liés .py, files.py, par exemple) et ils ont collé les définitions de champ * made dans le module de champs lui-même (d'où __init__.py).

34
dgrant

En utilisant le __init__.py fichier vous permet de rendre la structure interne du package invisible de l'extérieur. Si la structure interne change (par exemple parce que vous divisez un gros module en deux), il vous suffit de régler le __init__.py fichier, mais pas le code qui dépend du package. Vous pouvez également rendre des parties de votre colis invisibles, par ex. s'ils ne sont pas prêts pour une utilisation générale.

Notez que vous pouvez utiliser la commande del, donc un __init__.py peut ressembler à ceci:

from somemodule import some_function1, some_function2, SomeObject

del somemodule

Maintenant, si vous décidez de diviser somemodule 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 la même apparence qu'avant.

29
nikow