Скрипт против модуля
Вот объяснение. Коротко говоря, существует большая разница между непосредственным запуском файла Python и его импортом из другого места. Простое знание того, в каком каталоге находится файл, не определяет, в каком пакете он находится. Это зависит, кроме того, от того, как вы загружаете файл в Python (путем запуска или импорта).
Есть два способа загрузить файл Python: как сценарий верхнего уровня или как модуль. Файл загружается как сценарий верхнего уровня, если вы выполняете его напрямую, например, набрав python myfile.py
в командной строке. Он загружается как модуль, когда оператор 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
.)
person
BrenBarn
schedule
03.01.2013
def spam(): pass
, moduleA.py имеетdef eggs(): pass
. Я попытался выполнить пару команд из .something import something, но они не работали. Опять же, см. Pep-0328. - person   schedule 03.01.2013from .something import something
в интерактивном интерпретаторе, это не сработает. Относительный импорт можно использовать только внутри модулей, но не в интерактивном режиме. - person BrenBarn   schedule 03.01.2013__package__
и не могли бы вы предоставить рабочий пример). - person   schedule 03.01.2013