1
votes

python3.x: ModuleNotFoundError lors de l'importation d'un fichier depuis le répertoire parent

Je suis nouveau sur Python. Cela m'a vraiment dérouté!

Ma structure de répertoires est comme ceci:

import os
import sys
sys.path.append(os.path.abspath('..'))  

Quand j'importe a.py dans b.py avec du sous-paquet1 importer un , j'obtiens un ModuleNotFoundError . Il semble que je ne puisse pas importer un fichier du répertoire parent.

Certaines solutions suggèrent d'ajouter un fichier vide __init__.py dans chaque répertoire, mais cela ne fonctionne pas. Pour contourner le problème, j'ai mis ce qui suit dans chaque sous-fichier (c'est-à-dire a.py et b.py ) pour accéder au répertoire parent:

Project
   | - subpackage1
           |- a.py
   | - subpackage2
           |- b.py
   | - c.py  

J'ai essayé de sortir sys.path dans les sous-fichiers, il n'inclut que le chemin du fichier actuel et le chemin anaconda, donc je dois ajouter .. code> à sys.path .

Comment puis-je résoudre ce problème? Existe-t-il un moyen plus efficace?


0 commentaires

4 Réponses :


0
votes

Premièrement, vous devez créer le fichier __init__.py dans le sous-paquet1 pour déclarer qu'il s'agit d'un module

export PYTHONPATH=${PYTHONPATH}:${PWD}

Deuxièmement, vous pouvez essayer l'importation relative en python3 p >

# b.py
from ..subpackage1 import a

Ou vous pouvez ajouter votre répertoire actuel à $PYTHONPATH

touch subpackage1/__init__.py


0 commentaires

0
votes

Une façon d'accéder au sous-paquetage consiste à utiliser l'opérateur . qui monte jusqu'au premier répertoire du paquet ou du fichier. Ainsi, si la structure est

#b.py
from top_directory.package1.subpackage1 import a

statements...

Alors vous utilisez ce qui suit

top_directory
|- package1
   |- subpackage1
      |- a.py
|- package2
   |- subpackage2
      |- b.py

L'instruction from doit aller tout le jusqu'au répertoire supérieur couvrant à la fois a.py et b.py.


0 commentaires

2
votes

Supposons que nous ayons cette arborescence de fichiers et de répertoires:

$> pwd
/home/user/modules/submodule2
$> python3 b.py
hello from b
hello from a

Voici donc un exemple de la façon de faire l'importation depuis a.py inti b.py et vice-versa.

a.py

$> pwd
/home/user/modules/submodule1
$> python3 a.py
hello from a
hello from b

b.py

$> pwd
/home/user/modules
$> python3 main.py
hello from main
hello from a
hello from b

Et, main.py

from submodule1 import a
from submodule2 import b


def main():
    print('hello from main')
    a.hello_from_a()
    b.hello_from_b()


if __name__ == '__main__':
    main()

Démo:

Lorsque nous sommes au niveau supérieur et que nous essayons d'appeler main.py

try:
    from submodule1 import a
except ImportError:
    import sys
    sys.path.append(sys.path[0] + '/..')
    from submodule1 import a


def hello_from_b():
    print("hello from b")


if __name__ == '__main__':
    hello_from_b()
    a.hello_from_a()

Quand nous sommes dans / modules / submodule1 level et nous essayons d'appeler a.py

try:
    # Works when we're at the top lovel and we call main.py
    from submodule1 import b
except ImportError:
    # If we're not in the top level
    # And we're trying to call the file directly
    import sys
    # add the submodules to $PATH
    # sys.path[0] is the current file's path
    sys.path.append(sys.path[0] + '/..')
    from submodule2 import b


def hello_from_a():
    print('hello from a')


if __name__ == '__main__':
    hello_from_a()
    b.hello_from_b()

Quand nous sommes au niveau / modules / submodule2 et que nous ' vous essayez d'appeler b.py

$> tree
.
├── main.py
├── submodule1
│   ├── a.py
│   └── __init__.py
└── submodule2
    ├── b.py
    └── __init__.py

2 directories, 5 files


2 commentaires

Bonjour @Chiheb Nexus, merci pour votre réponse. Cela signifie que si je veux importer le fichier parent ou le fichier au même niveau, je dois ajouter le répertoire parent dans le sys.path, non?


Non, cela dépend de votre niveau. Mon exemple montre comment vous pouvez exécuter le code au niveau de chaque fichier.



2
votes

Le premier problème que vous rencontrez est dû au fait que du sous-paquetage1 importe une ligne dans votre module b.py .

b.py se trouve dans votre package subpackage2 , un package frère du subpackage1 . Donc, essayer d'exécuter à partir du sous-paquet1 importer un signifie que le sous-paquet1 est dans le sous-paquet2 , ce qui est incorrect. De plus, en python3, vous ne devez jamais utiliser d'importations relatives implicites car il ne les prend plus en charge, utilisez donc plutôt des importations relatives explicites.

L'ajout d'un __init__.py dans chaque dossier les transforme en packages python, et vous pouvez les garder vides. Vous voulez remplacer le du sous-paquet1 importer un par une importation relative explicite comme de ..subpackage1 importer un ou une importation absolue comme de Project.subpackage1 importer un . Ce sera la manière efficace et correcte d'écrire votre package, et vous pouvez le tester en écrivant un script qui importe Project et utilise ses sous-packages et modules.

Cependant, je suppose que vous exécutez b.py comme module principal pour tester les importations. Cela signifie que vous exécutez des lignes de commande qui ressemblent à: python b.py . L'exécuter comme ceci vous donne un chemin de recherche de module qui n'a aucun des chemins parents comme Projet . Cela vous amènerait à continuer à obtenir ModuleNotFoundErrors même s'il n'y a rien de mal techniquement avec votre package. C'est pourquoi vous avez besoin d'une solution de contournement sys.path.append (... qui ajoute manuellement votre chemin parent au chemin de recherche du module afin d'exécuter votre code b.py module en tant que module principal. Si cela vous aide à tester votre code, utilisez-le par tous les moyens, mais il est bien d'utiliser les importations relatives absolues et explicites car les modules d'un package sont censés fonctionner de cette façon.


2 commentaires

D'accord, merci beaucoup, votre réponse me clarifie un peu. Cela signifie que si b.py dans le subpackage2 a besoin d'un paramètre dans a.py , alors je devrais ajouter sys.path. ajouter (...) en tête de b.py , et si je ne le fais pas, je devrais déplacer a.py ou subpackage1 dans subpackage2 , non?


Tu es proche! Si vous souhaitez exécuter python b.py avec succès, vous pouvez utiliser la ligne sys.path.append (os.path.abspath ('..')) dans votre Module b.py qui place manuellement le chemin du package parent (le chemin "Projet" dans ce cas) dans le chemin de recherche de votre module. Cela vous permet d'importer n'importe quel module du subpackage1 dans votre module b.py lorsqu'il est exécuté en tant que module principal (exécutant le module comme python b.py ). Cependant, cela peut vous poser des problèmes lorsque vous essayez d'exécuter un script qui importe Project . Déplacer a.py dans subpackage1 est une option, mais éloigne le cœur de votre question initiale.