Итак, прежде всего, я предполагаю, что у вас есть __init__.py
внутри каждого каталога package
и subpackage
, чтобы сделать их настоящими "пакетами"; как указано здесь .
Теперь вы должны заметить, как subpackage
, содержащий module.py
, является фактическим подпакетом package
. Поэтому, когда вы делаете from package.dependency import ...
, вы пытаетесь импортировать из родительского пакета. Это не только плохая практика, но и путь, который вы используете в launcher.py
, предназначенный только для прямого и непосредственного нацеливания на module.py
, который не знает, что такое package
или даже subpackage
в этом отношении.
То, на что вы должны ориентироваться, это package
, который (опять же, при условии, что у вас есть __init__.py
там) будет загружаться как фактический «пакет». Делая все внутри него доступным ... после нескольких настроек.
В ваших __init__.py
вы должны выставить все, что вы хотите, чтобы этот модуль содержал. Например, в вашем package/__init__.py
должна быть строка from . import subpackage
. Это не только позволит вам делать такие вещи, как package.subpackage
, но и жизненно важно при загрузке содержимого subpackage
.
Следуя той же логике c, в вашем subpackage/__init__.py
должно быть from . import module
, загружая и выставляя module.py
, что позволяет вам делать package.subpackage.module
.
Это должно быть все, что вам нужно для правильной загрузки и доступа ко всему желаемому содержимому ... за исключением того, что вы также оборачиваете все что в experiment_n
папках. Здесь у вас есть два варианта: вы можете сделать experiment_n
пакетом с __init__.py
, выставить его package
и нацелиться на него с importlib
, или вы можете переименовать package
в experiment_n
и удалить верхнюю папку. Исходя из этого:
experiment_23
└── package
├── __init__.py
├── dependency.py
└── subpackage
├── __init__.py
└── module.py
К этому:
experiment_23
├── __init__.py
├── dependency.py
└── subpackage
├── __init__.py
└── module.py
Давайте сделаем перерыв в редактировании папки и посмотрим, как вы будете использовать нашу текущую итерацию в коде. Рассмотрим следующее launcher.py
:
import sys, os
import importlib.util
current_directory = os.path.dirname(os.path.realpath(__file__))
path_to_experiment = os.path.join(current_directory, 'reproduce/experiment_23')
path_to_experiment = os.path.join(path_to_experiment, '__init__.py') # package!
spec = importlib.util.spec_from_file_location('exp23', path_to_experiment, submodule_search_locations = [])
exp23 = importlib.util.module_from_spec(spec)
sys.modules[exp23.__name__] = exp23
# old one
spec.loader.exec_module(exp23)
exp23.subpackage.module.run()
# new one
import package.subpackage.module as exp
exp.run()
С основной функцией печати main
и воспроизведением одной печати exp23
.
Сначала мы составим наш path_to_experiment
, указывая на наш пакет __init__.py
. module_from_file_location
нужен файл , а не папка, поэтому мы не нацеливаемся на /expriment_23
напрямую. После, с фактическим именем (exp23
), мы получаем spec
с spec_from_file_location
, устанавливая submodule_search_locations
в пустой список, чтобы указать, что это пакет, как указано здесь . Наконец, загрузите наш модуль с помощью module_from_spec
.
Важно, чтобы мы добавили наш новый модуль в sys.modules
, чтобы относительный импорт (который мы используем) мог найти их родительский модуль.
Мы разрешаем наш модуль выполняет и вызывает его и функцию нашего нового модуля run
:
main
main
Кажется, что это не сработало, мы хотели, чтобы первый был exp23
Преступник эта from package.dependency import function
строка в нашем experiment_23/subpackage/module.py
. Здесь импортируется absolute
, а не relative
, что означает, что он будет искать / или импортировать "package"
in / to sys.modules
и использовать его. В этом случае это указывает непосредственно на наш основной пакет. Изменение его на from ..dependency import function
и повторное выполнение launcher.py
дает нам:
exp23
main
Success:)
Система импорта может быть довольно запутанной, тратя некоторое время на import system docs и importlib docs избавит вас от головной боли при возникновении подобной ситуации.
В качестве дополнительного предложения вы можете переместить module.py
в experiment_23
и из subpackage
и удалить subpackage
. Теперь вы можете сделать from .dependency import function
. Некоторые утверждают, что супер относительный импорт (с использованием более одного .
) является плохой практикой или, по крайней мере, демонстрирует недостаточное понимание структурирования пакетов.
Редактировать: Все изменения, примененные к experiment_23
, относятся к основному пакет эксперимента и все остальные experiment_n
...