it-swarm-fr.com

À quoi sert __init__.py?

À quoi sert __init__.py dans un répertoire source Python?

1947
Mat

Auparavant, il s'agissait d'une partie obligatoire d'un paquetage ( ancien, "paquetage standard" antérieur à la 3.3) , pas plus récent 3.3 "paquet d'espace de noms" ).

Voici la documentation.

Python définit deux types de packages, les packages standard et les packages d'espace de nommage. Les packages standard sont des packages traditionnels tels qu'ils existaient dans Python 3.2 et versions antérieures. Un paquet standard est généralement implémenté en tant que répertoire contenant un fichier __init__.py. Lorsqu’un package standard est importé, ce fichier __init__.py est exécuté de manière implicite et les objets qu’il définit sont liés à des noms figurant dans l’espace de noms du package. Le fichier __init__.py 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 il suffit de cliquer sur le lien, il contient un exemple, davantage d’informations et une explication des packages d’espaces de noms, type de packages sans __init__.py.

1267
Loki

Les fichiers nommés __init__.py servent à marquer les répertoires sur le disque comme étant les répertoires Python. Si vous avez les fichiers

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

et mydir est sur votre chemin, vous pouvez importer le code dans module.py comme

import spam.module

ou

from spam import module

Si vous supprimez le fichier __init__.py, Python ne recherchera plus de sous-modules à l'intérieur de ce répertoire. Toute tentative d'importation du module échouera.

Le fichier __init__.py est généralement vide, mais peut être utilisé pour exporter des parties sélectionnées du paquet sous un nom plus pratique, des fonctions de conservation, etc. Dans l'exemple ci-dessus, le contenu du module init peut être consulté

import spam

basé sur this

736
caritos

En plus de nommer un répertoire comme un package Python et de définir __all__, __init__.py vous permet de définir toute variable au niveau du package. Ce qui est 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érence à la philosophie pythonique du "bémol est meilleur que niché".

Un exemple

Voici un exemple tiré 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 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 identique à celui exécuté à l'intérieur ou à l'extérieur du répertoire du package "base de données".

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 du type "create_session.py" dans mon package de base de données et de démarrer de nouvelles sessions à l'aide de:

from database.create_session import Session
session = Session()

Lectures complémentaires

Il existe un fil reddit assez intéressant couvrant 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 les fichiers __init__.py doivent être très minces pour éviter de violer la philosophie "explicite vaut mieux que implicite".

438
Nathan Gould

Il y a 2 raisons principales pour __init__.py

  1. 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.

    your_package/
      __init__.py
      file1.py
      file2.py
        ...
      fileN.py
    
    # in __init__.py
    from file1 import *
    from file2 import *
    ...
    from fileN import *
    
    # in file1.py
    def add():
        pass
    

    alors d'autres peuvent appeler add () par

    from your_package import add
    

    sans savoir file1, comme

    from your_package.file1 import add
    
  2. Si vous voulez que quelque chose soit initialisé; par exemple, la journalisation (qui doit être placée au niveau supérieur):

    import logging.config
    logging.config.dictConfig(Your_logging_config)
    
170
flycee

Le fichier __init__.py fait en sorte que Python traite les répertoires qui le contiennent en tant que modules.

De plus, il s’agit du premier fichier chargé dans un module. Vous pouvez donc l’utiliser pour exécuter le code que vous souhaitez exécuter à chaque chargement d’un module ou spécifier les sous-modules à exporter.

101
Can Berk Güder

Depuis Python 3.3, __init__.py n'est plus nécessaire pour définir les répertoires en tant que packages Python importables.

Vérifier PEP 420: paquets d'espace de noms implicite :

Prise en charge native des répertoires de paquetages ne nécessitant pas de fichiers de marqueur __init__.py et pouvant s'étendre automatiquement sur plusieurs segments de chemin (inspirés de diverses approches tierces des paquets d’espaces de noms, comme décrit dans PEP 42 )

Voici le test:

$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3

>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module

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/
__init__.py n'est-il pas requis pour les packages dans Python 3?

78
zeekvfu

En Python, la définition du paquet est très simple. Comme Java, la structure hiérarchique et la structure de répertoires sont identiques. Mais vous devez avoir __init__.py dans un paquet. Je vais expliquer le fichier __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'il existe. Cela indique que le répertoire doit être considéré comme un paquet. Bien entendu, __init__.py peut é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 avoir couru:

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

function_X in module_n1 

Ensuite, nous avons suivi le paquetage hiérarchique et appelé module_n1 la fonction. Nous pouvons utiliser __init__.py dans subPackage_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

En utilisant * importing, le module est donc soumis au contenu de __init__.py.

51
Marcus Thornton

Bien que Python fonctionne sans fichier __init__.py, vous devez néanmoins en inclure un.

Il spécifie qu'un paquet doit être traité comme un module, donc incluez-le (même s'il est vide).

Il existe également un cas où vous pouvez réellement utiliser un fichier __init__.py:

Imaginez que vous ayez la structure de fichier suivante:

main_methods 
    |- methods.py

Et methods.py contenait ceci:

def foo():
    return 'foo'

Pour utiliser foo(), vous avez 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 avez-vous besoin (ou souhaitez-vous) de garder methods.py à l'intérieur de main_methods (runtimes/dépendances par exemple) mais vous ne souhaitez importer que main_methods.


Si vous avez changé le nom de methods.py en __init__.py, vous pouvez utiliser foo() simplement en important main_methods:

import main_methods
print(main_methods.foo()) # Prints 'foo'

Cela fonctionne parce que __init__.py est traité comme une partie du paquet.


Certains paquets Python le font réellement. Un exemple en est JSON , où exécuter import json importe réellement __init__.py à partir du package json ( voir la structure de fichier du package ici ):

Code source: Lib/json/__init__.py

42
Simon

__init__.py considérera le répertoire dans lequel il se trouve comme un module chargeable.

Pour ceux qui préfèrent lire du code, je mets le commentaire Two-Bit Alchemist ici.

$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$ 
$ rm /tmp/mydir/spam/__init__.py*
$ 
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>> 
37
B.Mr.W.

Cela facilite l’importation d’autres fichiers python. Lorsque vous avez placé ce fichier dans un répertoire (par exemple, stuff) contenant d’autres fichiers py, vous pouvez effectuer une opération similaire à l’importation stuff.other.

root\
    stuff\
         other.py

    morestuff\
         another.py

Sans ce __init__.py dans le répertoire, vous ne pourriez pas importer other.py, car Python ne sait pas où se trouve le code source du matériel et est incapable de le reconnaître en tant que package.

28
Epitaph

Un fichier __init__.py facilite les importations. Lorsqu'un __init__.py est présent dans un paquet, la fonction a() peut être importée du fichier b.py comme ceci:

from b import a

Sans cela, toutefois, 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
5
Alec Alameddine