Скрипт против модуля
Вот объяснение. Короткая версия заключается в том, что существует большая разница между прямым запуском файла 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.)