web-dev-qa-db-fra.com

Python - pourquoi puis-je importer des modules sans __init__.py du tout?

Je ne connais pas Python et je n'arrive toujours pas à comprendre pourquoi nous avons besoin d'un __init__.py fichier pour importer des modules. J'ai parcouru d'autres questions et réponses, telles que this .

Ce qui m'embrouille, c'est que je peux importer mes modules sans __init__py, donc pourquoi en ai-je besoin ?

Mon exemple,

index.py
   modules/
      hello/
          hello.py
          HelloWorld.py

index.py,

import os
import sys

root = os.path.dirname(__file__)
sys.path.append(root + "/modules/hello")

# IMPORTS MODULES
from hello import hello
from HelloWorld import HelloWorld

def application(environ, start_response):

    results = []

    results.append(hello())

    helloWorld = HelloWorld()
    results.append(helloWorld.sayHello())

    output = "<br/>".join(results)

    response_body = output

    status = '200 OK'

    response_headers = [('Content-Type', 'text/html'),
                       ('Content-Length', str(len(response_body)))]

    start_response(status, response_headers)

    return [response_body]

modules/hello/hello.py,

def hello():
    return 'Hello World from hello.py!'

modules/hello/HelloWorld.py,

# define a class
class HelloWorld:
    def __init__(self):
        self.message = 'Hello World from HelloWorld.py!'

    def sayHello(self):
        return self.message

Résultat,

Hello World from hello.py!
Hello World from HelloWorld.py!

Il suffit de ces deux lignes,

root = os.path.dirname(__file__)
sys.path.append(root + "/modules/hello")

Sans aucun des __init__py. Quelqu'un peut-il expliquer pourquoi cela fonctionne de cette façon?

Si __init__py est la bonne façon, que dois-je faire/changer dans mon code?

23
laukok

Je pense que c'est une bonne 'réponse' pour ce que je n'ai pas compris.

myMath/
    __init__.py
    adv/
        __init__.py
        sqrt.py
        fib.py
    add.py
    subtract.py
    multiply.py
    divide.py

myMath/__ init __. py

from add import add
from divide import division
from multiply import multiply
from subtract import subtract
from adv.fib import fibonacci
from adv.sqrt import squareroot

index.py

import sys

sys.path.append('C:\Users\mdriscoll\Documents')

import mymath

print mymath.add(4,5)
print mymath.division(4, 2)
print mymath.multiply(10, 5)
print mymath.fibonacci(8)
print mymath.squareroot(48)
2
laukok

__init__.py est pour packages. Un package contient une collection de modules associés. Si vous n'avez qu'un seul module que vous souhaitez utiliser, vous n'avez pas besoin d'utiliser __init__.py; il suffit de mettre le single .py fichier quelque part sur le chemin du système et vous pouvez l'importer.

Le but des packages n'est pas seulement de vous permettre d'importer les modules qu'ils contiennent. Il s'agit de regrouper les modules. Le principal avantage de ceci est que, si un module se trouve à l'intérieur d'un package, ce module peut importer d'autres modules du package à l'aide d'importations relatives. Si tu as foo.py et bar.py dans le même paquet, alors foo peut simplement faire from . import bar. Cela rend les importations intra-package plus compactes et plus faciles à réorganiser si vous restructurez le package ou changez son nom.

En outre, un avantage évident est. . . si vous en faites un package, vous n'avez pas à le faire sys.path trucs à chaque fois que vous voulez en importer quelque chose.

13
BrenBarn

Je pense que cela pourrait être dû à la version Python que vous utilisez. J'ai fait quelques expériences et j'ai découvert que la structure suivante était la suivante:

jedrzej@jedrzej-UX303LB ~/temp $ tree .
.
├── main.py
└── packages
    ├── file.py
    └── file.pyc

1 directory, 5 files

contenu de main.py:

import packages.file as p
p.fun()

et le contenu de file.py:

import sys
def fun():
  print(sys.path)

Lorsque j'exécute main.py avec Python 2.7.12 J'obtiens ImportError pendant l'exécution de main.py avec Python 3.5.2 fonctionne simplement.

Après avoir ajouté __init__.py dans le répertoire des packages, le code fonctionne avec les deux versions de Python.

8
jedruniu

Basé sur ce lien: Depuis Python 3.3

Autoriser les packages d'espace de noms implicites signifie que l'exigence de fournir un __init__.py le fichier peut être complètement supprimé

6
Anton Zobnin

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

modules/spam/__init__.py
modules/spam/module.py

et modules est sur votre chemin, vous pouvez importer le code dans module.py as

import spam.module

ou

from spam import module

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 le 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 avec

import spam

Et enfin voici ce que la documentation officielle a à dire sur ce fichier:

Le __init__.py les fichiers sont nécessaires pour que Python traite les répertoires comme contenant des packages; cela est fait pour empêcher les répertoires avec un nom commun, tel que chaîne, de masquer involontairement des modules valides qui se produisent plus tard sur le module chemin de recherche. Dans le cas le plus simple, __init__.py peut simplement être un fichier vide, mais il peut également exécuter le code d'initialisation du package ou définir le __all__ variable, décrite plus loin.

3
Shawn Mehan