python3.x: ModuleNotFoundError при импорте файла из родительского каталога - PullRequest
0 голосов
/ 24 января 2019

Я новичок в Python.Это действительно смутило меня!

Моя структура каталогов выглядит следующим образом:

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

Когда я импортирую a.py в b.py с from subpackage1 import a, я получаю ModuleNotFoundError .Кажется, я не могу импортировать файл из родительского каталога.

Некоторые решения предлагают добавить пустой файл __init__.py в каждый каталог, но это не работает.В качестве обходного пути я поместил в каждый субфайл следующее (то есть a.py и b.py) для доступа к родительскому каталогу:

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

Я попытался вывести sys.path в субфайлах,он включает в себя только текущий путь к файлу и путь к анаконде, поэтому мне нужно добавить .. к sys.path.

Как я могу решить эту проблему?Есть ли более эффективный способ?

Ответы [ 4 ]

0 голосов
/ 24 января 2019

Первая проблема, которую вы получите, связана с строкой from subpackage1 import a в вашем модуле b.py.

b.py находится в вашем пакете subpackage2, пакет с сестрой subpackage1. Поэтому попытка запустить from subpackage1 import a означает, что subpackage1 находится в пределах subpackage2, что неверно. Также как примечание: в python3 вы никогда не должны использовать неявный относительный импорт, так как он больше не поддерживает его, поэтому вместо этого используйте явный относительный импорт.

Добавление __init__.py в каждую папку превращает их в пакеты Python, и вы можете оставить их пустыми. Вы хотите заменить from subpackage1 import a либо явным относительным импортом, таким как from ..subpackage1 import a, либо абсолютным импортом, таким как from Project.subpackage1 import a. Это будет эффективный и правильный способ написания вашего пакета, и вы можете проверить его, написав скрипт, который импортирует Project и использует его подпакеты и модули.

Однако я предполагаю, что вы используете b.py в качестве основного модуля для проверки импорта. Это означает, что вы запускаете командные строки, которые выглядят так: python b.py. Запуск его таким образом дает вам путь поиска модуля, который не имеет ни одного из родительских путей, таких как Project. Это может привести к тому, что вы продолжите получать ModuleNotFoundErrors, даже если с вашим пакетом нет технических проблем. Вот почему вам нужен обходной путь sys.path.append(..., который вручную добавляет ваш родительский путь к пути поиска модуля, чтобы запустить ваш модуль b.py в качестве основного модуля. Если это поможет вам протестировать ваш код, то обязательно используйте его, но хорошо использовать абсолютный и явный относительный импорт, потому что модули в пакете должны работать таким образом.

0 голосов
/ 24 января 2019

Один из способов получить доступ к подпакету - использовать оператор ., идущий до самого верхнего пакета или каталога файлов.Таким образом, если структура имеет вид

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

, тогда вы используете следующее

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

statements...

. * * * * * * * * * * from Должен идти до верхнего каталога, охватывающего как a.py так и b.py.

0 голосов
/ 24 января 2019

Предположим, у нас есть это дерево файлов и каталогов:

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

2 directories, 5 files

Итак, вот пример того, как выполнить импорт из a.py inti b.py и наоборот.

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()

b.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()

И, 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()

Демо:

Когда мы находимся на верхнем уровне и пытаемся позвонить main.py

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

Когда мы находимся в /Уровень modules / submodule1, и мы пытаемся вызвать a.py

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

Когда мы находимся на уровне / modules / submodule2, и мы пытаемся вызвать b.py

$> pwd
/home/user/modules/submodule2
$> python3 b.py
hello from b
hello from a
0 голосов
/ 24 января 2019

Во-первых, вам нужно создать файл __init__.py в subpackage1, чтобы объявить, что это модуль

touch subpackage1/__init__.py

Во-вторых, вы можете попробовать относительный импорт в python3

# b.py
from ..subpackage1 import a

Или вы можете добавить свой текущий каталог в $PYTHONPATH

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