3727 votes

A quoi sert __init__.py ?

Qu'est-ce que __init__.py dans un répertoire de sources Python ?

27 votes

Selon le commentaire ci-dessous par @Rob_before_edits et ce fil de stackoverflow 37139786 il semble que init .py n'est plus nécessaire pour Python 3.3+.

26 votes

Paquet sans __init__ es paquet de noms et non un paquet régulier . Ce n'est pas la même chose. comme l'a souligné @methane avec un exemple ici .

0 votes

Pour ceux qui recherchent un cours gratuit et interactif sur Python , vous avez ici : theconstructsim.com/robotigniteacademy_learnros/

2018voto

Loki Points 7801

Il s'agissait autrefois d'une partie obligatoire d'un paquet ( ancien, pré-3.3 "paquet normal". pas newer 3.3+ "namespace package" (paquet de noms) ).

Voici la documentation.

Python définit deux types de paquets, les paquets réguliers et les paquets d'espace de noms. Les paquets réguliers sont des paquets traditionnels tels qu'ils existaient dans Python 3.2 et antérieurs. Un paquet régulier est typiquement implémenté comme un répertoire contenant un fichier __init__.py dossier. Lorsqu'un paquet régulier est importé, ce __init__.py est implicitement exécuté, et les objets qu'il définit sont liés à des noms dans l'espace de noms du paquet. Le site __init__.py peut contenir le même code Python que n'importe quel autre module, et Python ajoutera quelques attributs supplémentaires au module lors de son importation.

Mais il suffit de cliquer sur le lien, il contient un exemple, plus d'informations, et une explication des paquets de l'espace de nom, le genre de paquets sans __init__.py .

236 votes

Qu'est-ce que cela veut dire : "ceci est fait pour empêcher les répertoires avec un nom commun, tel que string, de cacher involontairement des modules valides qui se trouvent plus loin dans le chemin de recherche des modules" ?

127 votes

@CarlG Python recherche un liste de répertoires pour résoudre les noms dans, par exemple, les déclarations d'importation. Comme il peut s'agir de n'importe quel répertoire, et que des répertoires arbitraires peuvent être ajoutés par l'utilisateur final, les développeurs doivent se préoccuper des répertoires qui partagent un nom avec un module Python valide, comme 'string' dans l'exemple de la documentation. Pour pallier ce problème, il ignore les répertoires qui ne contiennent pas un fichier nommé _ _ init _ _.py (sans espace), même s'il est vide.

253 votes

@CarlG Essayez ceci. Créez un répertoire appelé 'datetime' et créez-y deux fichiers vierges, le fichier init.py (avec des underscores) et datetime.py. Maintenant, ouvrez un interpréteur, importez sys, et lancez sys.path.insert(0, '/path/to/datetime') en remplaçant ce chemin par le chemin du répertoire que vous venez de créer. Essayez maintenant quelque chose comme from datetime import datetime;datetime.now() . Vous devriez obtenir un AttributeError (parce qu'il importe maintenant votre fichier vierge). Si vous répétez ces étapes sans créer le fichier init vierge, cela ne se produira pas. C'est ce que l'on cherche à éviter.

1267voto

caritos Points 1488

Fichiers nommés __init__.py sont utilisés pour marquer les répertoires sur le disque comme des répertoires de paquets Python. Si vous avez les fichiers

mydir/spam/__init__.py
mydir/spam/module.py

y mydir est sur votre chemin, vous pouvez importer le code en module.py comme

import spam.module

ou

from spam import module

Si vous retirez le __init__.py Python ne recherchera plus les sous-modules dans ce répertoire, et les tentatives d'importation du module échoueront.

Le site __init__.py est généralement vide, mais peut être utilisé pour exporter certaines parties du paquetage sous un nom plus pratique, contenir des fonctions pratiques, etc. Dans l'exemple ci-dessus, le contenu du module init est accessible comme suit

import spam

sur la base de este

177 votes

Mise à jour : Le fichier __init__.py était nécessaire sous Python 2.X et l'est toujours sous Python 2.7.12 (je l'ai testé) mais ne l'est plus depuis (prétendument) Python 3.3, et ne l'est pas sous Python 3.4.3 (je l'ai testé). Voir stackoverflow.com/questions/37139786 pour plus de détails.

9 votes

Ne l'utilisez pas. Il s'agit d'un paquet "namespace", et non d'un paquet normal. Le paquet namespace est utilisé dans des cas très rares. Vous n'avez peut-être pas besoin de savoir quand l'utiliser. Utilisez simplement __init__.py .

6 votes

Cependant, si vous avez setup.py et vous utilisez find_packages() il est nécessaire d'avoir __init__.py dans chaque répertoire. Voir stackoverflow.com/a/56277323/7127824

674voto

Nathan Gould Points 587

En plus d'étiqueter un répertoire en tant que paquetage Python et de définir les éléments suivants __all__ , __init__.py vous permet de définir n'importe quelle variable au niveau du paquet. Cela est souvent pratique si un paquet définit quelque chose qui sera importé fréquemment, à la manière d'une API. Ce modèle favorise l'adhésion à la philosophie pythonique "flat is better than nested".

Un exemple

Voici un exemple tiré d'un de mes projets, dans lequel j'importe fréquemment une sessionmaker appelé Session pour interagir avec ma base de données. J'ai écrit un paquet "base de données" avec quelques modules :

database/
    __init__.py
    schema.py
    insertions.py
    queries.py

Mon __init__.py contient le code suivant :

import os

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)

Puisque je définis Session ici, je peux démarrer une nouvelle session en utilisant la syntaxe ci-dessous. Ce code serait le même exécuté à l'intérieur ou à l'extérieur du répertoire du paquet "database".

from database import Session
session = Session()

Bien sûr, c'est une petite commodité -- l'alternative serait de définir Session dans un nouveau fichier comme "create_session.py" dans mon paquetage de base de données, et démarrer de nouvelles sessions en utilisant :

from database.create_session import Session
session = Session()

Autres lectures

Il y a un fil de discussion intéressant sur reddit qui couvre les utilisations appropriées de __init__.py ici :

http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/

L'opinion majoritaire semble être que __init__.py Les fichiers doivent être très fins pour éviter de violer la philosophie "l'explicite vaut mieux que l'implicite".

8 votes

engine , sessionmaker , create_engine y os peuvent également tous être importés de database maintenant... on dirait que tu as fait un gâchis de cet espace de nom.

19 votes

@ArtOfWarfare, vous pouvez utiliser __all__ = [...] pour limiter ce qui est importé avec import * . Mais à part cela, oui, vous vous retrouvez avec un espace de noms de premier niveau désordonné.

0 votes

Puis-je savoir ce qu'est le "DATABASE URL" ? J'ai essayé de reproduire ce problème en entourant le create_engine de 'mysql+mysqldb://Root:python@localhost:3306/test' mais cela ne fonctionne pas. Merci.

187voto

Can Berk Güder Points 39887

Le site __init__.py fait que Python traite les répertoires qui le contiennent comme des modules.

En outre, il s'agit du premier fichier à être chargé dans un module, vous pouvez donc l'utiliser pour exécuter le code que vous souhaitez voir s'exécuter à chaque fois qu'un module est chargé, ou pour spécifier les sous-modules à exporter.

24 votes

Je pense que le init .py fait en sorte que Python traite les répertoires en tant que paquetes y no modules . Voir docs.python.org/3/tutorial/modules.html

14 votes

"tous les paquets sont des modules, mais tous les modules ne sont pas des paquets" -- bizarre, mais vrai.

74voto

Marcus Thornton Points 603

En Python, la définition d'un paquet est très simple. Comme en Java, la structure hiérarchique et la structure des répertoires sont les mêmes. Mais vous devez avoir __init__.py dans un paquet. Je vais expliquer le __init__.py avec l'exemple ci-dessous :

package_x/
|--  __init__.py
|--    subPackage_a/
|------  __init__.py
|------  module_m1.py
|--    subPackage_b/
|------  __init__.py
|------  module_n1.py
|------  module_n2.py
|------  module_n3.py

__init__.py peut être vide, tant qu'elle existe. Il indique que le répertoire doit être considéré comme un paquet. Bien sûr, __init__.py peut également définir le contenu approprié.

Si nous ajoutons une fonction dans le module_n1 :

def function_X():
    print "function_X in module_n1"
    return

Après avoir couru :

>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()

function_X in module_n1 

Ensuite, nous avons suivi le paquet hiérarchique et appelé la fonction module_n1. Nous pouvons utiliser __init__.py dans le sous-paquet_b comme ceci :

__all__ = ['module_n2', 'module_n3']

Après avoir couru :

>>>from package_x.subPackage_b import * 
>>>module_n1.function_X()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named module_n1

Par conséquent, en utilisant * l'importation, le paquet de module est soumis à __init__.py contenu.

0 votes

A quoi ressemblera mon setup.py pour faire le même import via la bibliothèque packagée ? from package_x.subPackage_b.module_n1 import function_X

0 votes

Donc, la principale leçon à retenir ici est "en utilisant * l'importation, le paquet de module est soumis à init .py contenu"

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