Так как я не совсем слежу, вот, по крайней мере, начало MCVE .Структура каталога проекта:
project/
__init__.py
run.py
package/
__init__.py
a.py
b.py
constants.py
Начиная с package
каталога (внутреннего) у меня есть:
__ init __. Py
from .a import ModelA
from .b import ModelB
a.py
from . import constants
class ModelA:
def __init__(self, a, b):
print("Instantiating Model A with {0} {1}".format(a, b))
print(" Pi:{0} hbar{1}".format(constants.pi, constants.hbar))
b.py
from . import constants
class ModelB:
def __init__(self, a, b):
print("Instantiating Model B with {0} {1}".format(a, b))
print(" Pi:{0} hbar{1}".format(constants.hbar, constants.pi))
constants.py
hbar = 1
pi = 3.14
Обратите внимание, что init содержит содержимое исключительно для удобства импорта project
в виде пакета и немедленного использования под ним имен ModelA
и ModelB
.Я так же легко оставил пустой файл __init__.py
, а затем from project.package.a import ModelA
.
Очень похоже на то, как это делается в project
dir.Верхний каталог (project
) содержит пустой файл __ init __. Py и:
run.py
#!/usr/bin/evn python
import argparse
import package
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('--param1', dest='param1')
parser.add_argument('--param2', dest='param2')
args = parser.parse_args()
package.ModelA(args.param1, args.param2)
package.ModelB(args.param2, args.param1)
Обратите внимание, чтоссылка на shebang может не понадобиться и зависит от ситуации при работе в кластере, где управление средой может сыграть свою роль.
Запустив это из терминала, вы получите
$:> python3 project/run.py --param1 10 --param2 100
Instantiating Model A with 10 100
Pi:3.14 hbar1
Instantiating Model B with 100 10
Pi:1 hbar3.14
Теперь возьмите это и улучшите то, что у вас есть, или восстановите то, что вы пытаетесь сделать, в упрощенном виде, как это (надеюсь, что вы нарушите пример), а затем опубликуйте, какая часть не работает и почему.
Редактировать
Позвольте мне предвосхитить решение утверждением, что подобные действия настраивают себя на неудачу.Мне кажется, что у вас есть файл run.py
, в котором вы хотите проанализировать аргументы, передаваемые через терминал, и использовать их для установки глобального состояния выполнения вашей программы.Вы не должны делать это почти всегда (единственное исключение, о котором я знаю, это то, что иногда и только иногда можно использовать для установки глобального состояния для движка или сеанса при подключении кбазы данных, но даже тогда это обычно не единственное или лучшее решение).
Именно по этой причине вам нужны модули и пакеты.Не должно быть никаких причин, по которым вы не сможете анализировать свои входные данные в run.py
и **, вызывая ** функциональность любого из ваших подмодулей.Сколько параметров принимают функции в a
и b
или принимают ли они и используют ли все или ни один из отправленных параметров, буквально не имеет значения.Вы можете отредактировать приведенный выше пример так, чтобы классам A и B требовались только 1, 3 или 10, или A 5 и B ни один из параметров, и он все равно работал бы.
a.py
from . import constants
from project.run import args
print("from A", args)
class ModelA:
def __init__(self, a, b):
print("Instantiating Model A with {0} {1}".format(a, b))
print(" Pi:{0} hbar{1}".format(constants.pi, constants.hbar))
b.py
from . import constants
from project.run import args
print("from B", args)
class ModelB:
def __init__(self, a, b):
print("Instantiating Model B with {0} {1}".format(a, b))
print(" Pi:{0} hbar{1}".format(constants.hbar, constants.pi))
run.py
#!/usr/bin/evn python
import argparse
from . import package
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('--param1', dest='param1')
parser.add_argument('--param2', dest='param2')
args = parser.parse_args()
if __name__ == "__main__":
package.ModelA(args.param1, args.param2)
package.ModelB(args.param2, args.param1)
И затем вызвать его как
$:> python3 -m project.run --param1 10 --param2 100
from A Namespace(param1='10', param2='100')
from B Namespace(param1='10', param2='100')
Instantiating Model A with 10 100
Pi:3.14 hbar1
Instantiating Model B with 100 10
Pi:1 hbar3.14
Обратите внимание, что мало что изменилось.Практически все, что мы действительно импортировали, args
из run.py
, используя абсолютные пути импорта вместо относительных, и затем мы переместили код выполнения в if __name__ == "__main__":
, чтобы он не вызывался при каждом импорте - только тот, который делает этоскрипт "основной" программы.Единственным большим и важным изменением было обращение к сценарию.Терминальная команда python3 -m project.run
импортирует модуль и затем запускает его как скрипт, тогда как ранее использованный python3 project/run.py
просто попытается запустить run.py
как скрипт.Когда модуль впервые импортируется, устанавливается значение __package__
;когда установлен __package__
, он разрешает явный относительный импорт, поэтому операторы from project.run import ...
работают, потому что теперь python знает, куда он должен обратиться, чтобы найти эти значения.Если run.py
запускается точно так же, как скрипт, то когда в старом run.py
Python вызывается оператор import package
, он переходит в каталог package/
, но не знает, что может потребоваться вернуться на один уровень вверхrun.py
) для поиска значений, определенных там, и импорта их на более низкий уровень в package/
dir.