Python должен знать каталог, в котором находится foo
, чтобы импортировать его. sys.path
перечисляет каталоги, в которых python будет искать.
Когда вы устанавливаете пакет, установщик беспокоится об этом - обычно помещая модуль в хорошо известный каталог или добавляя путь к пакету установки в sys.path
.
Когда вы запускаете скрипт, python автоматически добавляет путь этого скрипта к sys.path
, поэтому при запуске main.py
вы найдете foo
.
Как запустить модуль как __main__
Один из вариантов - сделать пакет устанавливаемым (setup.py, wheel, et c .... ) и используйте режим разработки ( "pip install --editable ./" vs "python setup.pyvelop" для некоторого обсуждения). Это то, что я делаю, когда разрабатываю что-то, что планирую сделать доступным для других.
Другой способ - добавить свой каталог в PYTHONPATH, возможно, даже при запуске программы. На linux это будет
PYTHONPATH=path/to/fooproject:$PYTHONPATH python foo/quux/corge.py
Еще один, и я тоже это делаю, это взломать путь в самом модуле. __file__
дает ваше имя файла относительно текущего рабочего каталога, и вы знаете, насколько глубоко вы находитесь в иерархии вашего пакета. Таким образом, вы можете просто сделать __file__
абсолютным и удалить пару имен каталогов
corge.py
import sys
import os
if __name__ == "__main__":
# I'm two levels deep in the package so package directory is
packagedir = os.path.abspath(os.path.join(os.path.dirname(__file__),
"..", ".."))
sys.path.insert(0, packagedir)
import foo
Наконец, не делайте этого в первую очередь. Когда вы запускаете corge.py
как скрипт, он получает другое пространство имен __main__
, чем foo.bar.corge
, импортированное как модуль. Его глобальные переменные / классы / функции загружаются дважды, и вы получаете разные в зависимости от того, вызываете ли вы их через пространство имен __main__
или foo.bar.corge
.
Лучше взять что-нибудь, что вам хотелось бы поместить в основную часть в corge.py
, сделать их отдельными скриптами. Например, вы можете добавить def main()
к своим модулям. В main.py
вы можете добавить опцию --run foo.bar.corge
, сообщающую main для импорта corge.py
, и запустить ее main()
. Для этого можно использовать подкоманды argparse
.