Selon les commentaires ci-dessous de @Rob_before_edits et ce thread stackoverflow 37139786 , il semble que init .py ne soit plus nécessaire pour Python 3.3+.
Python définit deux types de packages, les packages standard et les packages d'espace de noms. Les packages réguliers sont des packages traditionnels tels qu'ils existaient dans Python 3.2 et versions antérieures. Un package standard est généralement implémenté comme un répertoire contenant un __init__.pyfichier. Lorsqu'un package standard est importé, ce __init__.pyfichier est implicitement exécuté et les objets qu'il définit sont liés à des noms dans l'espace de noms du package. Le __init__.pyfichier peut contenir le même code Python que tout autre module peut contenir, et Python ajoutera des attributs supplémentaires au module lors de son importation.
Mais cliquez simplement sur le lien, il contient un exemple, plus d'informations et une explication des packages d'espace de noms, le type de packages sans __init__.py.
Qu'est-ce que cela signifie: "ceci est fait pour empêcher les répertoires avec un nom commun, comme une chaîne, de cacher involontairement des modules valides qui se produisent plus tard sur le chemin de recherche du module"?
Carl G
97
@CarlG Python recherche une liste de répertoires pour résoudre les noms, par exemple, les instructions d'importation. Étant donné que ceux-ci peuvent être n'importe quel répertoire et que des utilisateurs arbitraires peuvent être ajoutés par l'utilisateur final, les développeurs doivent se soucier des répertoires qui partagent un nom avec un module Python valide, tels que 'string' dans l'exemple de documentation. Pour y remédier, il ignore les répertoires qui ne contiennent pas de fichier nommé _ _ init _ _.py (pas d'espaces), même s'il est vide.
Two-Bit Alchemist
186
@CarlG Essayez ceci. Créez un répertoire appelé «datetime» et créez deux fichiers vides, le fichier init.py (avec des traits de soulignement) et datetime.py. Ouvrez maintenant un interpréteur, importez sys et lancez sys.path.insert(0, '/path/to/datetime'), en remplaçant ce chemin par le chemin vers le répertoire que vous venez de créer. Maintenant, essayez quelque chose comme from datetime import datetime;datetime.now(). Vous devriez obtenir une AttributeError (car il importe maintenant votre fichier vierge). Si vous deviez répéter ces étapes sans créer le fichier init vide, cela ne se produirait pas. C'est ce que l'on veut empêcher.
Two-Bit Alchemist
4
@ DarekNędza Vous avez quelque chose de mal configuré si vous ne pouvez pas simplement ouvrir un interpréteur Python et émettre from datetime import datetimesans erreur. C'est bien depuis la version 2.3!
Les fichiers nommés __init__.pysont utilisés pour marquer les répertoires sur le disque en tant que répertoires de packages Python. Si vous avez les fichiers
mydir/spam/__init__.py
mydir/spam/module.py
et mydirest sur votre chemin, vous pouvez importer le code en module.pytant que
import spam.module
ou
from spam import module
Si vous supprimez le __init__.pyfichier, Python ne recherchera plus de sous-modules dans ce répertoire, donc les tentatives d'importation du module échoueront.
Le __init__.pyfichier est généralement vide, mais peut être utilisé pour exporter des parties sélectionnées du package sous un nom plus pratique, conserver des fonctions pratiques, etc. Étant donné l'exemple ci-dessus, le contenu du module init est accessible comme
Mise à jour: le fichier __init__.pyétait requis sous Python 2.X et est toujours requis sous Python 2.7.12 (je l'ai testé) mais il n'est plus requis à partir de (prétendument) Python 3.3 et n'est plus requis sous Python 3.4.3 (I testé). Voir stackoverflow.com/questions/37139786 pour plus de détails.
Rob_before_edits
4
Ne l'utilisez pas. C'est un package "namespace", pas un package normal. Le package namespace est utilisé pour de très rares cas d'utilisation. Vous n'aurez peut-être pas besoin de savoir quand l'utiliser. Utilisez simplement __init__.py.
méthane
2
cependant si vous en avez setup.pyet que vous l'utilisez find_packages()il faut en avoir __init__.pydans chaque répertoire. Voir stackoverflow.com/a/56277323/7127824
techkuz
484
En plus d'étiqueter un répertoire en tant que package Python et de le définir __all__, __init__.pyvous permet de définir n'importe quelle variable au niveau du package. Cela est souvent pratique si un package 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 "plat est meilleur que imbriqué".
Un exemple
Voici un exemple de l'un de mes projets, dans lequel j'importe fréquemment un sessionmakerappelé Sessionpour interagir avec ma base de données. J'ai écrit un package "base de données" avec quelques modules:
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 Sessionici, je peux démarrer une nouvelle session en utilisant la syntaxe ci-dessous. Ce code serait le même exécuté de l'intérieur ou de l'extérieur du répertoire du package "base de données".
from database importSession
session =Session()
Bien sûr, c'est une petite commodité - l'alternative serait de définir Sessiondans un nouveau fichier comme "create_session.py" dans mon package de base de données, et de démarrer de nouvelles sessions en utilisant:
from database.create_session importSession
session =Session()
Lectures complémentaires
Il y a un fil reddit assez intéressant couvrant les utilisations appropriées d' __init__.pyici:
L'opinion majoritaire semble être que les __init__.pyfichiers doivent être très fins pour éviter de violer la philosophie "explicite vaut mieux qu'implicite".
engine, sessionmaker, create_engineEt ospeut tout aussi être importés d' databaseaujourd'hui ... semble que vous avez fait un gâchis de cet espace de noms.
ArtOfWarfare
9
@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 en désordre.
Nathan Gould
Puis-je savoir ce qu'est l'URL DE LA BASE DE DONNÉES? J'ai essayé de reproduire cela en enfermant le create_engine avec 'mysql + mysqldb: // root: python @ localhost: 3306 / test' mais cela ne fonctionne pas. Merci.
SunnyBoiz
2
Comment accéderiez- vous à la classe 'Session' définie dans init de l'intérieur du paquet, par exemple quieries.py?
vldbnc
253
Il y a 2 raisons principales pour __init__.py
Pour plus de commodité: les autres utilisateurs n'auront pas besoin de connaître l'emplacement exact de vos fonctions dans la hiérarchie de vos packages.
oh, avant de lire votre réponse, je pensais que l'appel explicite d'une fonction à partir de son emplacement était une bonne pratique.
Aerin
2
@Aerin, il serait préférable de ne pas considérer les déclarations courtes (ou, dans ce cas, les conclusions subjectives) comme toujours vraies. L'importation depuis __init__.pypeut être utile parfois, mais pas toujours.
Tobias Sette
2
Ces codes sont-ils exécutés au moment de l'importation ou de l'exécution?
user1559897
111
Le __init__.pyfichier fait que Python traite les répertoires le contenant 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 exécuter à chaque fois qu'un module est chargé, ou spécifier les sous-modules à exporter.
Prise en charge native des répertoires de packages qui ne nécessitent pas de __init__.pyfichiers de marqueurs et peuvent s'étendre automatiquement sur plusieurs segments de chemin (inspirés de diverses approches tierces des packages d'espace de noms, comme décrit dans PEP 420 )
En Python, la définition de package est très simple. Comme Java, la structure hiérarchique et la structure de répertoires sont les mêmes. Mais vous devez avoir __init__.pydans un paquet. Je vais expliquer le __init__.pyfichier avec l'exemple ci-dessous:
__init__.pypeut être vide, tant qu'il existe. Il indique que le répertoire doit être considéré comme un package. Bien sûr, __init__.pypeut également définir le contenu approprié.
Si nous ajoutons une fonction dans module_n1:
def function_X():print"function_X in module_n1"return
Après l'exécution:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
Ensuite, nous avons suivi le package de hiérarchie et appelé module_n1 la fonction. Nous pouvons utiliser __init__.pydans subPackage_b comme ceci:
__all__ =['module_n2','module_n3']
Après l'exécution:
>>>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 package du module est soumis au __init__.pycontenu.
À quoi ressemblera mon setup.py pour effectuer la même importation via la bibliothèque empaquetée? from package_x.subPackage_b.module_n1 import function_X
technazi
donc la clé à retenir ici est "en utilisant * l'importation, le package du module est soumis au contenu init .py"
Minnie
54
Bien que Python fonctionne sans __init__.pyfichier, vous devez toujours en inclure un.
Il spécifie qu'un paquet doit être traité comme un module, alors incluez-le donc (même s'il est vide).
Il y a aussi un cas où vous pouvez réellement utiliser un __init__.pyfichier:
Imaginez que vous ayez la structure de fichiers suivante:
main_methods
|- methods.py
Et methods.pycontenait ceci:
def foo():return'foo'
Pour l'utiliser, foo()vous auriez besoin de l'un des éléments suivants:
from main_methods.methods import foo # Call with foo()from main_methods import methods # Call with methods.foo()import main_methods.methods # Call with main_methods.methods.foo()
Peut-être y avez-vous besoin (ou voulez-vous) de rester à l' methods.pyintérieur main_methods(runtimes / dépendances par exemple) mais vous voulez seulement importer main_methods.
Si vous avez changé le nom de methods.pyen, __init__.pyvous pouvez l'utiliser foo()en important simplement main_methods:
import main_methods
print(main_methods.foo())# Prints 'foo'
Cela fonctionne car __init__.pyest traité comme faisant partie du package.
Certains packages Python le font. Un exemple est avec JSON , où l'exécution import jsonest en fait une importation à __init__.pypartir du jsonpackage ( voir la structure du fichier du package ici ):
Il facilite l'importation d'autres fichiers python. Lorsque vous avez placé ce fichier dans un répertoire (disons stuff) contenant d'autres fichiers py, vous pouvez faire quelque chose comme importer stuff.other.
root\
stuff\
other.py
morestuff\
another.py
Sans cela __init__.pyà l'intérieur du répertoire, vous ne pourriez pas importer other.py, car Python ne sait pas où se trouve le code source du contenu et ne peut pas le reconnaître en tant que package.
J'ai la même structure dans mon projet (python 3.4) mais je ne peux pas faire un autre.py voir other.py. Comment dois-je effectuer l'importation? de root.stuff importer autre? Il fonctionne en mode débogage VSCode mais pas en ligne de commande. Des idées?
rodrigorf
10
Un __init__.pyfichier facilite les importations. Quand un __init__.pyest présent dans un package, la fonction a()peut être importée à partir d'un fichier b.pycomme ceci:
from b import a
Sans cela, cependant, vous ne pouvez pas importer directement. Vous devez modifier le chemin du système:
import sys
sys.path.insert(0,'path/to/b.py')from b import a
que voulez-vous dire par "la fonction a () peut être importée à partir du fichier b.py [extrait] Sans elle, cependant, vous ne pouvez pas importer directement. "? Je peux importer la fonction a () du fichier b.py sans __init__.py.
Réponses:
Il faisait partie intégrante d'un package ( ancien, "package normal" antérieur à 3.3 , et non plus récent "package d'espace de noms" 3.3+ ).
Voici la documentation.
Mais cliquez simplement sur le lien, il contient un exemple, plus d'informations et une explication des packages d'espace de noms, le type de packages sans
__init__.py
.la source
sys.path.insert(0, '/path/to/datetime')
, en remplaçant ce chemin par le chemin vers le répertoire que vous venez de créer. Maintenant, essayez quelque chose commefrom datetime import datetime;datetime.now()
. Vous devriez obtenir une AttributeError (car il importe maintenant votre fichier vierge). Si vous deviez répéter ces étapes sans créer le fichier init vide, cela ne se produirait pas. C'est ce que l'on veut empêcher.from datetime import datetime
sans erreur. C'est bien depuis la version 2.3!builtins
liste les fonctions et classes intégrées, pas les modules intégrés (cf. docs.python.org/3/tutorial/modules.html#the-dir-function ). Si vous voulez lister les modules intégrés , faites-leimport sys; print(sys.builtin_module_names)
(cf. docs.python.org/3/library/sys.html#sys.builtin_module_names ).Les fichiers nommés
__init__.py
sont utilisés pour marquer les répertoires sur le disque en tant que répertoires de packages Python. Si vous avez les fichierset
mydir
est sur votre chemin, vous pouvez importer le code enmodule.py
tant queou
Si vous supprimez le
__init__.py
fichier, Python ne recherchera plus de sous-modules dans ce répertoire, donc les tentatives d'importation du module échoueront.Le
__init__.py
fichier est généralement vide, mais peut être utilisé pour exporter des parties sélectionnées du package sous un nom plus pratique, conserver des fonctions pratiques, etc. Étant donné l'exemple ci-dessus, le contenu du module init est accessible commebasé sur cela
la source
__init__.py
était requis sous Python 2.X et est toujours requis sous Python 2.7.12 (je l'ai testé) mais il n'est plus requis à partir de (prétendument) Python 3.3 et n'est plus requis sous Python 3.4.3 (I testé). Voir stackoverflow.com/questions/37139786 pour plus de détails.__init__.py
.setup.py
et que vous l'utilisezfind_packages()
il faut en avoir__init__.py
dans chaque répertoire. Voir stackoverflow.com/a/56277323/7127824En plus d'étiqueter un répertoire en tant que package Python et de le définir
__all__
,__init__.py
vous permet de définir n'importe quelle variable au niveau du package. Cela est souvent pratique si un package 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 "plat est meilleur que imbriqué".Un exemple
Voici un exemple de l'un de mes projets, dans lequel j'importe fréquemment un
sessionmaker
appeléSession
pour interagir avec ma base de données. J'ai écrit un package "base de données" avec quelques modules:Mon
__init__.py
contient le code suivant: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é de l'intérieur ou de l'extérieur du répertoire du package "base de données".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 package de base de données, et de démarrer de nouvelles sessions en utilisant:Lectures complémentaires
Il y a un fil reddit assez intéressant couvrant les utilisations appropriées d'
__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 les
__init__.py
fichiers doivent être très fins pour éviter de violer la philosophie "explicite vaut mieux qu'implicite".la source
engine
,sessionmaker
,create_engine
Etos
peut tout aussi être importés d'database
aujourd'hui ... semble que vous avez fait un gâchis de cet espace de noms.__all__ = [...]
pour limiter ce qui est importé avecimport *
. Mais à part cela, oui, vous vous retrouvez avec un espace de noms de premier niveau en désordre.Il y a 2 raisons principales pour
__init__.py
Pour plus de commodité: les autres utilisateurs n'auront pas besoin de connaître l'emplacement exact de vos fonctions dans la hiérarchie de vos packages.
alors d'autres peuvent appeler add () par
sans connaître file1, comme
Si vous voulez que quelque chose soit initialisé; par exemple, la journalisation (qui devrait être placée au niveau supérieur):
la source
__init__.py
peut être utile parfois, mais pas toujours.Le
__init__.py
fichier fait que Python traite les répertoires le contenant 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 exécuter à chaque fois qu'un module est chargé, ou spécifier les sous-modules à exporter.
la source
Depuis Python 3.3, il
__init__.py
n'est plus nécessaire de définir les répertoires en tant que packages Python importables.Vérifiez PEP 420: packages implicites d'espace de noms :
Voici le test:
références:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Is __init__. py non requis pour les packages en Python 3?
la source
En Python, la définition de package est très simple. Comme Java, la structure hiérarchique et la structure de répertoires sont les mêmes. Mais vous devez avoir
__init__.py
dans un paquet. Je vais expliquer le__init__.py
fichier avec l'exemple ci-dessous:__init__.py
peut être vide, tant qu'il existe. Il indique que le répertoire doit être considéré comme un package. Bien sûr,__init__.py
peut également définir le contenu approprié.Si nous ajoutons une fonction dans module_n1:
Après l'exécution:
Ensuite, nous avons suivi le package de hiérarchie et appelé module_n1 la fonction. Nous pouvons utiliser
__init__.py
dans subPackage_b comme ceci:Après l'exécution:
Par conséquent, en utilisant * l'importation, le package du module est soumis au
__init__.py
contenu.la source
from package_x.subPackage_b.module_n1 import function_X
Bien que Python fonctionne sans
__init__.py
fichier, vous devez toujours en inclure un.Il spécifie qu'un paquet doit être traité comme un module, alors incluez-le donc (même s'il est vide).
Il y a aussi un cas où vous pouvez réellement utiliser un
__init__.py
fichier:Imaginez que vous ayez la structure de fichiers suivante:
Et
methods.py
contenait ceci:Pour l'utiliser,
foo()
vous auriez besoin de l'un des éléments suivants:Peut-être y avez-vous besoin (ou voulez-vous) de rester à l'
methods.py
intérieurmain_methods
(runtimes / dépendances par exemple) mais vous voulez seulement importermain_methods
.Si vous avez changé le nom de
methods.py
en,__init__.py
vous pouvez l'utiliserfoo()
en important simplementmain_methods
:Cela fonctionne car
__init__.py
est traité comme faisant partie du package.Certains packages Python le font. Un exemple est avec JSON , où l'exécution
import json
est en fait une importation à__init__.py
partir dujson
package ( voir la structure du fichier du package ici ):la source
__init__.py
traitera le répertoire dans lequel il se trouve comme un module chargeable.Pour les personnes qui préfèrent lire le code, je mets ici le commentaire de Two-Bit Alchemist .
la source
Il facilite l'importation d'autres fichiers python. Lorsque vous avez placé ce fichier dans un répertoire (disons stuff) contenant d'autres fichiers py, vous pouvez faire quelque chose comme importer stuff.other.
Sans cela
__init__.py
à l'intérieur du répertoire, vous ne pourriez pas importer other.py, car Python ne sait pas où se trouve le code source du contenu et ne peut pas le reconnaître en tant que package.la source
Un
__init__.py
fichier facilite les importations. Quand un__init__.py
est présent dans un package, la fonctiona()
peut être importée à partir d'un fichierb.py
comme ceci:Sans cela, cependant, vous ne pouvez pas importer directement. Vous devez modifier le chemin du système:
la source