J'essaie actuellement de travailler dans Python3 et d'utiliser des importations absolues pour importer un module dans un autre, mais l'erreur ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package
. Considérez cette structure de projet:
proj
__init__.py3 (empty)
moduleA.py3
moduleB.py3
moduleA.py3
from .moduleB import ModuleB
ModuleB.hello()
moduleB.py3
class ModuleB:
def hello():
print("hello world")
Ensuite, lancer python3 moduleA.py3
donne l'erreur. Qu'est-ce qui doit être changé ici?
.moduleB
est une importation relative. Relative ne fonctionne que lorsque le module parent est importé ou chargé en premier. Cela signifie que vous devez importer proj
quelque part dans votre environnement d'exécution actuel. Lorsque vous utilisez la commande python3 moduleA.py3
, vous ne pouvez pas importer le module parent. Vous pouvez:
from proj.moduleB import moduleB
OUrun.py
, pour appeler from proj import moduleA
Bonne chance dans votre voyage au pays de Python.
En plus de la réponse de md-sabuj-sarker, il existe un très bon exemple dans documentation sur les modules Python .
Voici ce que disent les docs sur intra-package-references :
Notez que les importations relatives sont basées sur le nom du module actuel. Le nom du module principal étant toujours
"__main__"
, les modules destinés à être utilisés comme module principal d'une application Python doivent toujours utiliser des importations absolues.
Si vous exécutez python3 moduleA.py3
, moduleA
est utilisé comme module principal. L'utilisation de l'importation absolue semble donc être la meilleure chose à faire.
Cependant, sachez que cette importation absolue (from package.module import something
) échoue si, pour une raison quelconque, le package contient un fichier de module portant le même nom que le package (au moins, sur mon Python 3.7). Ainsi, par exemple, cela échouera si vous avez (en utilisant l'exemple du PO):
proj/
__init__.py (empty)
proj.py (same name as package)
moduleA.py
moduleB.py
auquel cas vous obtiendriez:
ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package
Vous pouvez également supprimer le .
de from .moduleB import
, comme suggéré ici et ici , ce qui semble fonctionner, bien que mon PyCharm (2018.2.4) ) marque ceci comme une "référence non résolue" et ne parvient pas à se compléter automatiquement.
Je développe un projet qui est en fait un package Python pouvant être installé via pip , mais il expose également une commande interface de ligne. Je n'ai pas de problèmes à exécuter mon projet après l'avoir installé avec pip install .
, mais bon, qui fait cela à chaque fois après avoir modifié quelque chose dans l'un des fichiers du projet? Il me fallait tout faire par python mypackage/main.py
simple.
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
J'ai essayé d'importer quelques fonctions dans main.py
à partir de mon module common.py
. J'ai essayé différentes configurations qui ont donné des erreurs différentes, et je veux partager avec vous mes observations et laisser une note rapide pour moi aussi.
Le premier que j'ai essayé était une importation relative:
from .common import my_func
J'ai exécuté mon application avec simple: python mypackage/main.py
. Malheureusement, cela a donné l'erreur suivante:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
La cause de ce problème est que le main.py
a été exécuté directement par la commande python
, devenant ainsi le module principal nommé __main__
. Si nous connectons ces informations à l'importation relative que nous avons utilisée, nous obtenons ce que nous avons dans le message d'erreur: __main__.common
. Ceci est expliqué dans le documentation Python :
Notez que les importations relatives sont basées sur le nom du module actuel. Le nom du module principal étant toujours
__main__
, les modules destinés à être utilisés comme module principal d'une application Python doivent toujours utiliser des importations absolues.
Lorsque j'ai installé mon paquet avec pip install .
et que je l'ai ensuite exécuté, cela a parfaitement fonctionné. J'ai également pu importer le module mypackage.main
dans une console Python. Donc, il semble qu'il y ait un problème à l'exécuter directement.
Suivons les conseils de la documentation et changeons l'instruction d'importation en une autre:
from common import my_func
Si nous essayons maintenant d'exécuter ceci comme avant: python mypackage/main.py
, alors cela fonctionnera comme prévu! Cependant, il y a une mise en garde lorsque, comme moi, vous développez quelque chose qui doit fonctionner comme un outil de ligne de commande autonome après l'avoir installé avec pip . J'ai installé mon paquet avec pip install .
puis j'ai essayé de l'exécuter ...
ModuleNotFoundError: No module named 'common'
Pire encore, lorsque j'ai ouvert une console Python et tenté d'importer le module main
manuellement (import mypackage.main
), la même erreur que ci-dessus s'est produite. La raison en est simple: common
n'est plus une importation relative, donc Python essaie de le trouver dans les packages installés. Nous n'avons pas un tel forfait, c'est pourquoi il échoue.
La solution avec une importation absolue ne fonctionne bien que lorsque vous créez une application Python typique exécutée avec une commande python
.
Il existe également une troisième possibilité pour importer le module common
:
from mypackage.common import my_func
Ce n’est pas très différent de l’approche relative à l’importation relative , tant que nous le faisons à partir du contexte de mypackage
. Et encore une fois, essayer de lancer ceci avec python mypackage/main.py
se termine de la même manière:
ModuleNotFoundError: No module named 'mypackage'
Comme cela peut être irritant, l'interprète a raison, vous n'avez pas installé un tel logiciel.
Il suffit d’utiliser des importations absolues (sans le point) et tout ira bien.
Utilisez des importations relatives, ou des importations avec un nom de package au début, car vous en avez besoin de cette manière lors de l'installation de votre application. Quand il s'agit d'exécuter un tel module en développement, Python peut être exécuté avec l'option -m
:
-m mod : run library module as a script (terminates option list)
Ainsi, au lieu de python mypackage/main.py
, procédez comme suit: python -m mypackage.main
.
Peut-être que vous pouvez le faire avant d'importer le module:
moduleA.py3
import os
import re
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from moduleB import ModuleB
ModuleB.hello()
Ajouter le répertoire en cours au répertoire de l'environnement