Импорт Python внутри и вне пакета

#python #python-3.x #import

#python #python-3.x #импорт

Вопрос:

Это моя ситуация. У меня есть следующая структура каталогов:

 $ls -R                                                                                                                                                                                                                                                      .:
driver.py  package

./package:
dependent.py  __init__.py  standalone.py
  

driver.py:

 #!/usr/bin/env python

from package.dependent import add_n

if __name__=='__main__':
  print(add_n(2,2))
  

dependent.py:

 #!/usr/bin/env python

from standalone import add_1

def add_n(x, n):
  for _ in range(n):
    x = add_1(x)
  return x
  

standalone.py:

 #!/usr/bin/env python

def add_1(x):
  return x 1
  

Теперь, в зависимости от моего варианта использования, я хочу запустить dependent.py напрямую или импортировать его в driver.py . Это проблема, с которой я сталкиваюсь:

  • Запуск dependent.py работает, только если при импорте нет точки add_1 . Если он есть, он выдает следующую ошибку:
 Traceback (most recent call last):
  File "dependent.py", line 3, in <module>
    from .standalone import add_1
ModuleNotFoundError: No module named '__main__.standalone'; '__main__' is not a package
  
  • Запуск package.py работает, только если при импорте есть точка add_1 . Если такового нет, выдается следующая ошибка:
 Traceback (most recent call last):
  File "driver.py", line 3, in <module>
    from package.dependent import add_n
  File "/home/su0/scratch/package/dependent.py", line 3, in <module>
    from standalone import add_1
ModuleNotFoundError: No module named 'standalone'
  

Я хочу, чтобы работали оба сценария. Это потому, что в реальном проекте внутри пакета есть зависимости, которые импортируют другие модули. И я хочу иметь возможность импортировать его также как пакет. Приветствуется любая помощь.

Спасибо.

Комментарии:

1. Что pwd в этом случае?

2. Извините, я не понимаю. Это просто некоторый каталог (каталог в моем доме).

Ответ №1:

Лучше всего было бы действительно упаковать код, а затем использовать абсолютный импорт в dependent.py . Однако в качестве обходного пути вы можете использовать один из следующих вариантов:

Расширяем путь в driver.py

Перед import package.dependent вы можете добавить следующие строки:

 import sys
sys.path.append('package')
  

Затем используйте оператор import без точек в dependent.py . Это работает, поскольку теперь package находится на пути к поиску модулей, включая standalone.py .

Используйте условный импорт в dependent.py

Вы можете изменить импорт в dependent.py следующим образом:

 if __name__ == '__main__':
    from standalone import ...
else:
    from .standalone import ...
  

Комментарии:

1. Выполняется ли условный импорт в самом верху, чтобы заменить исходную инструкцию import?

2. Да, он должен заменить исходный. Он может использоваться где угодно, но, очевидно, должен быть выполнен до того, как вы попытаетесь использовать импортированную функцию. В любом случае я бы предпочел использовать вариант 1 (упаковать код) или вариант 2 (расширить sys.path ); вариант 3 (условный импорт) подразумевает, что dependent.py «знает», что он будет импортирован куда-то еще, но тогда вы все равно могли бы просто поместить код в отдельный модуль.