Относительно импорта в Python 3 не работает

у меня есть следующий каталог:

mydirectory
├── __init__.py
├── file1.py 
└── file2.py

у меня есть функция f, определенная в file1.py.

Если, в file2.py-я делаю

from .file1 import f

Я получаю следующую ошибку:

SystemError: Родительский модуль " не загружен, не может выполнять относительные импорт

почему? И как заставить его работать?

4 ответов


С file1 и file2 находятся в одном каталоге, вам даже не нужно иметь . Если вы собираетесь наращивать, то оставьте его там.

импортировать что-то в файл в том же каталоге, просто сделать такой

from file1 import f

т. е. вам не нужно делать относительный путь .file1 потому что они находятся в той же директории.

если ваша основная функция, скрипт или что-то еще, это будет работать все приложение в другом каталоге вам придется сделать все относительно того, где это выполняется.


запуск модулей внутри пакета в качестве исполняемых файлов-это плохая практика.

когда вы разрабатываете что-то, вы либо создаете библиотеку, которая предназначена для импорта другими программами, и поэтому нет смысла разрешать выполнение ее подмодулей напрямую, либо создаете исполняемый файл, и в этом случае нет причин делать его частью пакета.

именно поэтому setup.py вы различаете пакеты и скрипты. Пакеты идите под site-packages в то время как скрипты будут установлены под /usr/bin (или аналогичное местоположение в зависимости от ОС).

моя рекомендация, таким образом, использовать следующий макет:

/
├── mydirectory
|    ├── __init__.py
|    ├── file1.py 
└── file2.py

здесь file2.py импорт file1.py как и любой другой код, который хочет использовать библиотеку mydirectory С абсолютное импорт:

from mydirectory.file1 import f

когда вы пишите setup.py скрипт для проекта вы просто перечисляете mydirectory в пакет и file2.py как сценарий и все будет работать. Нет необходимости возиться с sys.path.

если вы когда-либо по какой-то причине действительно хотите запустить подмодуль пакета, правильный способ сделать это-использовать -m переключатель:

python -m mydirectory.file1

это загружает весь пакет, а затем выполняет модуль как скрипт, позволяя относительному импорту успешно.

лично я бы этого не делал. Также потому, что многие люди даже не знают, что вы можете это сделать и в конечном итоге получите такая же ошибка, как и вы, и думаете, что пакет сломан.


относительно принятого в настоящее время ответа, в котором говорится, что вы должны просто использовать подразумевается относительный импорт from file1 import f, потому что он будет работать, так как они находятся в той же директории:

это неправильно!

  • это не работа в python3, где неявный относительный импорт запрещен и, безусловно, сломается, если у вас есть установлена file1 модуль (так как он будет импортирован вместо вашего модуля!).
  • даже если он работает в file1 не будет рассматриваться как часть . Это can вопрос.

    например, если file1 использует pickle, имя пакета важно для правильной загрузки / выгрузки данных.


при запуске исходного файла python запрещено импортировать другой файл, который находится в текущем пакете, используя относительный импорт.

на документация Он сказал:

обратите внимание, что относительный импорт основан на имени текущего модуля. Поскольку имя основного модуля всегда " _ _ main__", модули, предназначенные для использования в качестве основного модуля приложения Python, всегда должны использовать абсолютный импорт.

Так, как @mrKelley сказал, вам нужно использовать абсолютный импорт в такой ситуации.


myproject/

mypackage
├── __init__.py
├── file1.py
├── file2.py 
└── file3.py

mymainscript.py

пример импорта из одного файла в другой

#file1.py
from myproject import file2
from myproject.file3 import MyClass

импортируйте пример пакета в mainscript

#mymainscript.py
import mypackage

https://docs.python.org/3/tutorial/modules.html#packages

https://docs.python.org/3/reference/import.html#regular-packages

https://docs.python.org/3/reference/simple_stmts.html#the-import-statement

https://docs.python.org/3/glossary.html#term-import-path

переменная sys.path-это список строк, определяющих путь поиска интерпретатора для модулей. Он инициализируется путем по умолчанию, взятым из переменной среды PYTHONPATH, или из встроенного значения по умолчанию, если PYTHONPATH не установлен. Вы можете изменить его с помощью стандартных операций списка:

import sys
sys.path.append('/ufs/guido/lib/python')
sys.path.insert(0, '/ufs/guido/myhaxxlib/python')

вставка его в начале имеет преимущество гарантировать, что путь ищется перед другими (даже встроенными) в случае конфликтов именования.