Скрипт против модуля
Вот объяснение. Короткая версия заключается в том, что существует большая разница между прямым запуском файла Python и импортом этого файла из другого места. Знание того, в каком каталоге находится файл, не определяет, в каком пакете Python, по его мнению, находится. Это зависит, кроме того, от того, как вы загрузите файл в Python (запустив или импортировав).
Есть два способа загрузки файла Python: как скрипт верхнего уровня или как модуль. Файл загружается как скрипт верхнего уровня, если вы выполняете его напрямую, например, вводя python myfile.py
в командной строке. Он загружается как модуль, если вы это делаете python -m myfile
, или если он загружается, когда import
оператор встречается внутри какого-то другого файла. За один раз может быть только один скрипт верхнего уровня; скрипт верхнего уровня - это файл Python, который вы запустили для начала.
Именование
Когда файл загружен, ему присваивается имя (которое хранится в его __name__
атрибуте). Если он был загружен как скрипт верхнего уровня, его имя - __main__
. Если он был загружен как модуль, его именем является имя файла, которому предшествуют имена любых пакетов / подпакетов, частью которых он является, разделенных точками.
Так, например, в вашем примере:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
если вы импортировали moduleX
(примечание: импортировано , не выполнено напрямую), его имя будет package.subpackage1.moduleX
. Если вы импортировали moduleA
, его имя будет package.moduleA
. Однако, если вы запускаете напрямую moduleX
из командной строки, его имя будет вместо этого __main__
, а если вы запускаете напрямую moduleA
из командной строки, его имя будет __main__
. Когда модуль запускается как скрипт верхнего уровня, он теряет свое обычное имя, а вместо него его имя __main__
.
Доступ к модулю НЕ через содержащий его пакет
Есть дополнительная складка: имя модуля зависит от того, был ли он импортирован «напрямую» из каталога, в котором он находится, или импортирован через пакет. Это имеет значение, только если вы запустите Python в каталоге и попытаетесь импортировать файл в тот же каталог (или его подкаталог). Например, если вы запустите интерпретатор Python в каталоге, package/subpackage1
а затем сделаете import moduleX
, имя moduleX
будет просто moduleX
, а не package.subpackage1.moduleX
. Это потому, что Python добавляет текущий каталог к своему пути поиска при запуске; если он находит импортируемый модуль в текущем каталоге, он не будет знать, что этот каталог является частью пакета, и информация о пакете не станет частью имени модуля.
Особый случай - если вы запускаете интерпретатор в интерактивном режиме (например, просто набираете python
и начинаете вводить код Python на лету). В этом случае имя этого интерактивного сеанса __main__
.
Теперь самое важное для вашего сообщения об ошибке: если имя модуля не имеет точек, оно не считается частью пакета . Неважно, где файл на самом деле находится на диске. Все, что имеет значение, это как его имя, и его имя зависит от того, как вы его загрузили.
Теперь посмотрите на цитату, которую вы включили в свой вопрос:
Относительный импорт использует атрибут имени модуля для определения позиции этого модуля в иерархии пакетов. Если имя модуля не содержит никакой информации о пакете (например, для него установлено значение «main»), то относительный импорт разрешается так, как если бы модуль был модулем верхнего уровня, независимо от того, где этот модуль фактически расположен в файловой системе.
Относительный импорт ...
Относительный импорт использовать модуль имя , чтобы определить , где он находится в пакете. Когда вы используете относительный импорт from .. import foo
, точки указывают на увеличение количества уровней в иерархии пакетов. Например, если имя вашего текущего модуля package.subpackage1.moduleX
, то ..moduleA
будет означать package.moduleA
. Чтобы from .. import
работал, имя модуля должно содержать как минимум столько же точек, сколько в import
операторе.
... являются относительными только в пакете
Тем не менее, если ваш модуль называется __main__
, он не считается в пакете. Его имя не имеет точек, и поэтому вы не можете использовать from .. import
операторы внутри него. Если вы попытаетесь это сделать, вы получите ошибку «относительный импорт в не пакет».
Скрипты не могут импортировать относительные
Что вы, вероятно, сделали, вы пытались запустить moduleX
или что-то подобное из командной строки. Когда вы это сделали, для его имени было установлено значение __main__
, что означает, что относительный импорт в нем завершится неудачно, поскольку его имя не показывает, что он находится в пакете. Обратите внимание, что это также произойдет, если вы запустите Python из того же каталога, где находится модуль, а затем попытаетесь импортировать этот модуль, потому что, как описано выше, Python найдет модуль в текущем каталоге «слишком рано», не осознавая, что это часть пакета.
Также помните, что когда вы запускаете интерактивный интерпретатор, «имя» этого интерактивного сеанса всегда __main__
. Таким образом, вы не можете выполнять относительный импорт напрямую из интерактивного сеанса . Относительный импорт предназначен только для использования в файлах модуля.
Два решения:
Если вы действительно хотите запускать moduleX
напрямую, но хотите, чтобы он считался частью пакета, вы можете это сделать python -m package.subpackage1.moduleX
. -m
Говорит Python , чтобы загрузить его как модуль, а не как сценарий верхнего уровня.
Или, возможно, вы на самом деле не хотите запускать moduleX
, вы просто хотите запустить какой-нибудь другой скрипт, скажем myfile.py
, который использует функции внутри moduleX
. Если это так, поместите myfile.py
куда-нибудь еще - не в package
каталог - и запустите его. Если внутри myfile.py
вы делаете что-то вроде from package.moduleA import spam
, это будет работать нормально.
Ноты
Для любого из этих решений каталог пакета ( package
в вашем примере) должен быть доступен из пути поиска модуля Python ( sys.path
). Если это не так, вы вообще не сможете использовать что-либо в пакете надежно.
Начиная с Python 2.6, «имя» модуля для разрешения пакетов определяется не только его __name__
атрибутами, но и __package__
атрибутом. Вот почему я избегаю использовать явный символ __name__
для ссылки на «имя» модуля. Начиная с Python 2.6, «имя» модуля является эффективным __package__ + '.' + __name__
, или просто __name__
если __package__
есть None
.)