266 votes

__init__.py n'est-il pas nécessaire pour les paquets de Python 3.3+ ?

J'utilise Python 3.5.1. J'ai lu le document et la section sur les paquets ici : https://docs.python.org/3/tutorial/modules.html#packages

Maintenant, j'ai la structure suivante :

/home/wujek/Playground/a/b/module.py

module.py :

class Foo:
    def __init__(self):
        print('initializing Foo')

Maintenant, alors que dans /home/wujek/Playground :

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

De même, maintenant à la maison, superfolder de Playground :

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

En fait, je peux faire toutes sortes de choses :

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

Pourquoi cela fonctionne-t-il ? Je pensais qu'il devait y avoir __init__.py (des fichiers vides fonctionneraient) dans les deux a y b para module.py pour être importable lorsque le chemin d'accès Python pointe vers le fichier Playground dossier ?

Cela semble avoir changé depuis Python 2.7 :

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

Avec __init__.py dans les deux ~/Playground/a y ~/Playground/a/b cela fonctionne bien.

274voto

AndreasLukas Points 2221

Vue d'ensemble

La réponse de @Mike est correcte mais trop imprécis . Il est vrai que Python 3.3+ supporte Paquets d'espaces de noms implicites qui lui permet de créer un paquet sans __init__.py fichier. C'est ce qu'on appelle un paquet de noms à l'inverse d'un paquet régulier qui dispose d'un __init__.py (vide ou non).

Cependant, la création d'un paquet de noms ne devrait être faite QUE si elle est nécessaire. Pour la plupart des cas d'utilisation et des développeurs, cela ne s'applique pas. VIDE __init__.py sans tenir compte des fichiers.

Cas d'utilisation du paquet d'espace-nom

Pour démontrer la différence entre les deux types de paquets python, prenons l'exemple suivant :

google_pubsub/              <- Package 1
    google/                 <- Namespace package (there is no __init__.py)
        cloud/              <- Namespace package (there is no __init__.py)
            pubsub/         <- Regular package (with __init__.py)
                __init__.py <- Required to make the package a regular package
                foo.py

google_storage/             <- Package 2
    google/                 <- Namespace package (there is no __init__.py)
        cloud/              <- Namespace package (there is no __init__.py)
            storage/        <- Regular package (with __init__.py)
                __init__.py <- Required to make the package a regular package
                bar.py

google_pubsub y google_storage sont des paquets distincts mais ils partagent le même espace de nom google/cloud . Afin de partager le même espace de noms, il est nécessaire de faire de chaque répertoire du chemin commun un paquet de l'espace de noms, c'est-à-dire google/ y cloud/ . Cela devrait être le seul cas d'utilisation pour la création de paquets d'espace de nom, sinon, il n'y a pas besoin de cela.

Il est crucial qu'il n'y ait pas __init__py dans le google y google/cloud de sorte que les deux répertoires puissent être interprétés comme étant paquets d'espace-nom . Dans Python 3.3+, n'importe quel répertoire du répertoire sys.path dont le nom correspond au nom du paquet recherché seront reconnus comme des modules et des sous-paquets contribuant à ce paquet. Par conséquent, lorsque vous importez à la fois de google_pubsub y google_storage l'interpréteur Python sera capable de les trouver.

Ceci est différent de paquets réguliers qui sont autonomes, c'est-à-dire que toutes les parties se trouvent dans la même hiérarchie de répertoires. Lorsque vous importez un paquetage et que l'interpréteur Python rencontre un sous-répertoire dans le répertoire sys.path avec un __init__.py il créera un paquet dans un seul répertoire contenant uniquement les modules de ce répertoire, plutôt que de trouver tous les sous-répertoires nommés de manière appropriée en dehors de ce répertoire. Cela convient parfaitement aux paquets qui ne veulent pas partager un espace de nom. . Je vous recommande vivement de jeter un coup d'œil à Pièges pour les imprudents dans le système d'importation de Python pour mieux comprendre comment l'importation Python se comporte avec les paquets réguliers et les espaces de noms et ce que __init__.py les pièges à surveiller.

Résumé

  • Sauter seulement __init__.py si vous voulez créer des fichiers paquets d'espace-nom . Ne créez des paquets d'espace de nom que si vous avez différentes bibliothèques qui résident à différents endroits et que vous voulez que chacune d'entre elles contribue à un sous-paquet du paquet parent, c'est-à-dire le paquet d'espace de nom.
  • Continuez à ajouter du vide __init__py à vos répertoires parce que 99% du temps vous voulez juste créer paquets réguliers . De plus, des outils Python tels que mypy y pytest exigez des vides __init__.py pour interpréter la structure du code en conséquence. Cela peut conduire à des erreurs bizarres si cela n'est pas fait avec soin.

Ressources

Ma réponse ne fait qu'effleurer la façon dont paquets réguliers y paquets d'espace-nom Pour en savoir plus, consultez les ressources suivantes :

2 votes

Supposons que j'ai run_script.py dans le même répertoire que parent_package donc je peux juste importer comme from parent_package.child_package import child1 sin __init__.py ?

0 votes

Est-ce que le but est de pouvoir écrire child_package.some_function même si some_function est définie dans childX.py ? En d'autres termes, cela évite de demander à l'utilisateur de connaître les différents fichiers de child_package ? ?

0 votes

Ouais, je ne comprends pas pourquoi tu ferais child1.py , child2.py au lieu de simplement mettre leur code ensemble dans __init__ .py directement.

246voto

Mike Müller Points 2963

Python 3.3+ possède Paquets d'espaces de noms implicites qui lui permettent de créer un paquet sans __init__.py fichier.

Autoriser les paquets d'espaces de noms implicites signifie que l'exigence de fournir un __init__.py fichier peut être complètement abandonné et affectée... .

L'ancienne méthode avec __init__.py fonctionnent toujours comme dans Python 2.

13 votes

Je vais lire le document, mais il est un peu long. Est-il possible de le résumer rapidement ? Pourriez-vous simplement me dire : est-ce que le document soutient toujours init .py, ou les ignore complètement ? S'il les prend en charge, quelle est la différence de fonctionnalité et pourquoi cette dualité ?

1 votes

Oui, ça marche toujours. Donc tous vos paquets Python 2 avec __init__.py fonctionneront en termes d'importations (autre différence entre Python 2 et 3 non prise en compte ici).

3 votes

Le tutoriel devrait donc probablement être mis à jour. Un bug de documentation a-t-il été ouvert à ce sujet ?

25voto

trthhrtz Points 500

Si vous avez setup.py dans votre projet et vous utilisez find_packages() en son sein, il est nécessaire de disposer d'un __init__.py dans chaque répertoire pour que les paquets soient automatiquement trouvés.

Les paquets ne sont reconnus que s'ils comprennent un __init__.py fichier

UPD : Si vous voulez utiliser des paquets d'espaces de noms implicites sans __init__.py il suffit d'utiliser find_namespace_packages() au lieu de

Docs

9voto

Mi-La Points 81

Je dirais que l'on devrait omettre le __init__.py seulement si l'on veut avoir le paquet d'espace de noms implicite . Si vous ne savez pas ce qu'il signifie, vous n'en voulez probablement pas et vous devriez donc continuer à utiliser l'option __init__.py même dans Python 3.

4voto

Prahlad Yeri Points 1232

D'après mon expérience, même avec python 3.3+, un fichier vide __init__.py est encore nécessaire parfois. C'est le cas lorsque vous souhaitez référencer un sous-dossier comme un paquet. Par exemple, lorsque j'ai exécuté python -m test.foo cela n'a pas fonctionné jusqu'à ce que je crée un fichier vide de __init__.py sous le dossier de test. Et je parle ici de la version 3.6.6 qui est assez récente.

En dehors de cela, même pour des raisons de compatibilité avec le code source existant ou les directives du projet, il est agréable de disposer d'un fichier vide de type __init__.py dans le dossier de votre paquetage.

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