105 votes

Ajout de code à __init__.py

Je suis en train de regarder 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 vide __init__.py pour spécifier que le répertoire courant est un paquet. 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 la section __init__.py . Pourquoi ? Cela ne donne-t-il pas un aspect désordonné aux choses ? Y a-t-il une raison pour laquelle ce code dans __init__.py ?

83voto

Alexander Kojevnikov Points 9389

Toutes les importations en __init__.py sont rendus disponibles lorsque vous importez le paquet (répertoire) qui les contient.

Ejemplo:

./dir/__init__.py :

import something

./test.py :

import dir
# can now use dir.something

EDIT : j'ai oublié de mentionner que le code dans le fichier __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 placer le code d'initialisation au niveau du paquet.

EDIT2 : dgrant m'a signalé une confusion possible dans mon exemple. Dans __init__.py import something peut importer n'importe quel module, pas nécessairement du paquet. Par exemple, nous pouvons le remplacer par import datetime alors 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()

En résumé, tous les noms attribués dans __init__.py Les modules, fonctions ou classes importés sont automatiquement disponibles dans l'espace de nom du paquet lorsque vous importez le paquet ou un module du paquet.

45voto

dgrant Points 857

Ce n'est qu'une préférence personnelle, qui dépend de la disposition de vos modules python.

Disons que vous avez un module appelé erikutils . Il y a deux façons d'être un module, 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 en son sein. Ensuite, disons que vous avez un groupe de modules appelés fileutils , procutils , parseutils et vous voulez que ceux-ci soient des sous-modules sous erikutils . Vous créez donc des fichiers .py appelés fileutils.py , procutils.py y parseutils.py :

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

Peut-être que vous avez quelques fonctions qui n'ont pas leur place dans le système de gestion de l'information. fileutils , procutils ou parseutils modules. 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()

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

Dans django, le meilleur exemple auquel je pense est le suivant django.db.models.fields . TOUTES les classes de champs *de django sont définies dans le fichier __init__.py dans le fichier django/db/models/fields répertoire. Je suppose qu'ils ont fait ça parce qu'ils ne voulaient pas tout mettre dans un hypothétique django/db/models/fields.py Ils l'ont donc divisé en plusieurs sous-modules ( related.py , files.py par exemple) et ils ont collé les définitions de *champs faites dans le module des champs lui-même (d'où, __init__.py ).

30voto

nikow Points 8887

Utilisation de la __init__.py vous permet de rendre la structure interne du paquet invisible de l'extérieur. Si la structure interne change (par exemple, parce que vous divisez un module gras en deux), il vous suffit d'ajuster le fichier __init__.py mais pas le code qui dépend du paquet. Vous pouvez également rendre invisible certaines parties de votre paquet, par exemple si elles ne sont pas prêtes pour un usage général.

Notez que vous pouvez utiliser l'option del de sorte qu'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 le même aspect.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X