TL; DR:
__init__.py
:
import foo
import bar
__all__ = ["foo", "bar"]
foo.py
:
import subprocess
from os import environ
# your code here
bar.py
import subprocess
from os import environ
# your code here
Должно быть, я чего-то упускаю, что позволяет мне ссылаться на подпроцесс с уровня выше?
Нет, это ожидаемое поведение.
import
загружает модуль (если его еще нет), кэширует его в sys.modules
(то же самое) и связывает импортированные имена в текущем пространстве имен. Каждый модуль Python имеет (или «есть») свое собственное пространство имен (нет реального «глобального» пространства имен). Итак, вы должны импортировать то, что вам нужно, в каждый модуль, т.е. если foo.py требуется subprocess
, он должен явно импортировать его.
Сначала это может показаться утомительным, нов долгосрочной перспективе это действительно помогает в отношении поддержки и сопровождения - вам просто нужно прочитать импорт в верхней части вашего модуля (pep 08: всегда помещать все импорты в начало модуля), чтобы узнать, откуда происходит имя.
Кроме того, вы не должны использовать импорт звездочек (он же * подстановочный знак from xxx import *
) где-либо еще, кроме как в вашей оболочке Python (и даже тогда ...) - это бомба замедленного действия. Не только потому, что вы не знаете, откуда происходит каждое имя, но и потому, что это верный способ связать уже импортированное имя. Представьте, что ваш модуль foo определяет функцию «func». Где-то у вас есть "из импорта foo *; из импорта бара *", затем в коде вызов функции. Теперь кто-то редактирует bar.py и добавляет (отдельную) функцию «func», и внезапно вы вызываете ошибку, потому что вы не вызываете ожидаемый «func». Теперь наслаждайтесь отладкой этого ... И примеры из реальной жизни, как правило, немного сложнее, чем это.
Так что, если вам нравится ваше душевное равновесие, не ленитесь, не пытайтесь быть умными,просто сделайте простую очевидную вещь: явно импортируйте имена, которые вам интересны, в верхней части ваших модулей.
(здесь, сделали это и т. д.)