__Init__.py n'est-il pas requis pour les packages dans Python 3.3+

195

J'utilise Python 3.5.1. J'ai lu le document et la section package 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, pendant que vous êtes /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 ça marche? Je pensais qu'il devait y avoir des __init__.pyfichiers (des fichiers vides fonctionneraient) dans les deux aet bpour module.pyêtre importables lorsque le chemin Python pointe vers le Playgrounddossier?

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 les __init__.pydeux ~/Playground/aet ~/Playground/a/bcela fonctionne très bien.

wujek
la source

Réponses:

192

Python 3.3+ a des packages d'espace de noms implicites qui lui permettent de créer un package sans __init__.pyfichier.

Autoriser les packages d'espaces de noms implicites signifie que l'exigence de fournir un __init__.pyfichier peut être complètement supprimée et affectée ....

L'ancienne méthode avec les __init__.pyfichiers fonctionne toujours comme dans Python 2.

Mike Müller
la source
10
Je vais lire le document, mais c'est un peu long. Est-il possible de résumer rapidement? Pourriez-vous me dire: est-ce qu'il prend toujours en charge init .py ou les ignore complètement? S'il les prend en charge, quelle est la différence de fonctionnalité et pourquoi cette dualité?
wujek
3
Le tutoriel devrait donc probablement être mis à jour. Un bug de documentation est-il ouvert pour cela?
Michel Samia
4
Je suis toujours contrarié que cela défie la Zen Of Python ligne 2: Explicit is better than implicit.....
JayRizzo
5
@JayRizzo Mais: "Bien que l'aspect pratique l'emporte sur la pureté."
Mike Müller
19
@JayRizzo IMO c'est encore plus explicite. Parfois, il arrive de faire des choses d'initialisation __init__.py, parfois non. Dans Python 3, lorsque j'ai besoin de ces éléments, je crée un nouveau __init__.pyavec un code spécifique, sinon je n'en ai pas. Cela est pratique pour savoir visuellement quels packages ont un init personnalisé. Au lieu de cela, dans python 2, je dois toujours placer un __init__.py(souvent vide), ce qui en fait un grand nombre et finalement plus difficile de me souvenir où vous avez placé votre code d'initialisation. Cela devrait également correspondre à "Il devrait y avoir une - et de préférence une seule - façon évidente de le faire.".
Paolo
148

IMPORTANT

La réponse de @ Mike est correcte mais trop imprécise. Il est vrai que Python 3.3+ prend en charge les packages d'espace de noms implicites qui lui permettent de créer un package sans __init__.pyfichier.

Cependant, ceci s'applique UNIQUEMENT aux fichiers VIDE__init__.py . Les fichiers VIDE__init__.py ne sont donc plus nécessaires et peuvent être omis. Si vous souhaitez exécuter un script d'initialisation particulier lorsque le package ou l'un de ses modules ou sous-packages sont importés, vous avez toujours besoin d'un __init__.pyfichier. C'est une excellente réponse à Stack Overflow pour expliquer pourquoi vous voudriez utiliser un __init__.pyfichier pour effectuer une initialisation supplémentaire au cas où vous vous demandez pourquoi cela est utile.

Exemple de structure de répertoire:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

EXEMPLES

Les exemples ci-dessous montrent comment le script d'initialisation est exécuté lorsque le child_packageou l'un de ses modules est importé.

Exemple 1 :

from parent_package import child_package  # prints "from parent"

Exemple 2 :

from parent_package.child_package import child1  # prints "from parent"
arauter
la source
2
Supposons que j'ai run_script.pydans le même répertoire que parent_package, puis-je importer comme from parent_package.child_package import child1sans __init__.py?
mrgloom
Le but est-il de vous permettre d'écrire child_package.some_function même si some_function est défini dans childX.py? En d'autres termes, cela évite de demander à l'utilisateur de connaître les différents fichiers de child_package? ?
johnbakers
Ouais, je ne comprends pas pourquoi vous feriez child1.py, child2.pyau lieu de simplement mettre leur code ensemble dans __init__.py directement.
binki
Les déclarations d'importation ne devraient-elles pas __init__être des importations relatives, par exemple from . import child1? L'importation absolue me donne ModuleNotFoundError(en Python 3.6)
Halbeard
5
D'après mon expérience, même avec python 3.3+, un vide __init__.pyest encore parfois nécessaire, comme lorsque vous voulez faire référence à un sous-dossier en tant que package. Par exemple, si je l'exécute, python -m test.foocela ne fonctionnait pas jusqu'à ce que j'aie créé un vide __init__.pysous le dossier de test. Et je parle de la version 3.6.6 ici!
Prahlad Yeri
7

Si vous en avez setup.pydans votre projet et que vous l'utilisez find_packages(), il est nécessaire d'avoir un __init__.pyfichier dans chaque répertoire pour que les packages soient automatiquement trouvés.

Les packages ne sont reconnus que s'ils incluent un __init__.pyfichier

UPD : Si vous souhaitez utiliser des packages d'espace de noms implicites sans __init__.pyavoir à utiliser à la find_namespace_packages()place

Docs

techkuz
la source
2

Je dirais que l'on devrait omettre le __init__.pyseul si l'on veut avoir le package d'espace de noms implicite . Si vous ne savez pas ce que cela signifie, vous ne le voulez probablement pas et vous devriez donc continuer à utiliser le __init__.pymême en Python 3.

Mi-La
la source