Я был здесь:
- http://www.python.org/dev/peps/pep-0328/
- http://docs.python.org/2/tutorial/modules.html#packages
- Пакеты Python: относительный импорт
- Пример кода относительного импорта Python не работает
- Окончательный ответ на относительный импорт Python
- Относительный импорт в Python
- Python: отключение относительного импорта
и множество URL-адресов, которые я не копировал, некоторые на SO, некоторые на других сайтах, когда я думал, что быстро найду решение.
Постоянно повторяющийся вопрос заключается в следующем: в Windows 7, 32-битном Python 2.7.3, как мне решить это сообщение «Попытка относительного импорта в не пакет»? Я построил точную копию пакета на pep-0328:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
Импорт был сделан из консоли.
Я сделал функции с именем спам и яйца в соответствующих модулях. Естественно, это не сработало. Ответ, по-видимому, находится в 4-м URL-адресе, который я перечислил, но это все мои выпускники. Был такой ответ на одном из URL, которые я посетил:
Относительный импорт использует атрибут имени модуля для определения позиции этого модуля в иерархии пакетов. Если имя модуля не содержит никакой информации о пакете (например, для него установлено значение «main»), то относительный импорт разрешается так, как если бы модуль был модулем верхнего уровня, независимо от того, где этот модуль фактически расположен в файловой системе.
Приведенный выше ответ выглядит многообещающе, но для меня это все иероглифы. Итак, мой вопрос, как сделать так, чтобы Python не возвращал мне «Попытка относительного импорта в неупакованном виде»? есть ответ, который включает в себя -m, предположительно.
Может кто-нибудь сказать мне, почему Python выдает это сообщение об ошибке, что означает «не пакет», почему и как вы определяете «пакет», и точный ответ, выраженный в терминах, достаточно простых для понимания в детском саду .
источник
def spam(): pass
, moduleA.py имеетdef eggs(): pass
. Я пытался выполнить пару команд «из. Что-то импортировать что-то», но они не работали. Снова смотрите pep-0328.from .something import something
в интерактивном переводчике, это не сработает. Относительный импорт может использоваться только внутри модулей, но не в интерактивном режиме.Ответы:
Скрипт против модуля
Вот объяснение. Короткая версия заключается в том, что существует большая разница между прямым запуском файла Python и импортом этого файла из другого места. Знание того, в каком каталоге находится файл, не определяет, в каком пакете Python, по его мнению, находится. Это зависит, кроме того, от того, как вы загрузите файл в Python (запустив или импортировав).
Есть два способа загрузки файла Python: как скрипт верхнего уровня или как модуль. Файл загружается как скрипт верхнего уровня, если вы выполняете его напрямую, например, вводя
python myfile.py
в командной строке. Он загружается как модуль, если вы это делаетеpython -m myfile
, или если он загружается, когдаimport
оператор встречается внутри какого-то другого файла. За один раз может быть только один скрипт верхнего уровня; скрипт верхнего уровня - это файл Python, который вы запустили для начала.Именование
Когда файл загружен, ему присваивается имя (которое хранится в его
__name__
атрибуте). Если он был загружен как скрипт верхнего уровня, его имя -__main__
. Если он был загружен как модуль, его именем является имя файла, которому предшествуют имена любых пакетов / подпакетов, частью которых он является, разделенных точками.Так, например, в вашем примере:
если вы импортировали
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__
.Теперь самое важное для вашего сообщения об ошибке: если имя модуля не имеет точек, оно не считается частью пакета . Неважно, где файл на самом деле находится на диске. Все, что имеет значение, это как его имя, и его имя зависит от того, как вы его загрузили.
Теперь посмотрите на цитату, которую вы включили в свой вопрос:
Относительный импорт ...
Относительный импорт использовать модуль имя , чтобы определить , где он находится в пакете. Когда вы используете относительный импорт
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
.)источник
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.
Это принципиально тревожно. Что такого сложного в просмотре текущего каталога? Python должен быть способен на это. Это исправлено в версии 3х?__package__ = 'package.subpackage1'
или тому подобное. Тогда только этот файл будет всегда рассматриваться как часть этого пакета , даже если работать напрямую. Если у вас есть другие вопросы о__package__
вас, возможно, вы захотите задать отдельный вопрос, поскольку мы обсуждаем вопрос вашего первоначального вопроса здесь.__name__
иsys.path
. В частности, сpython -m pkg.mod
,__name__
установлено__main__
, неpkg.mod
; относительный импорт разрешается с использованием,__package__
а не__name__
в этом случае. Кроме того, Python добавляет каталог скрипта, а не текущий каталогsys.path
при запускеpython path/to/script.py
; он добавляет текущий каталогsys.path
при запуске большинства других способов, в том числеpython -m pkg.mod
.Это действительно проблема внутри Python. Истоки путаницы в том, что люди ошибочно принимают относительное значение в качестве относительного пути, а это не так.
Например, когда вы пишете в faa.py :
Это имеет смысл, только если faa.py был идентифицирован и загружен python во время выполнения как часть пакета. В этом случае имя модуля для faa.py бы, например , some_packagename.faa . Если файл был загружен только потому, что он находится в текущем каталоге, когда запускается python, то его имя не будет ссылаться на какой-либо пакет, и в итоге относительный импорт завершится неудачно.
Простое решение для ссылки на модули в текущем каталоге, это использовать это:
источник
from __future__ import absolute_import
том, чтобы заставить пользователя правильно использовать ваш код ... так что вы всегда можете это сделатьfrom . import foo
Вот общий рецепт, измененный в качестве примера, который я сейчас использую для работы с библиотеками Python, написанными как пакеты, которые содержат взаимозависимые файлы, и я хочу иметь возможность тестировать их части по частям. Давайте назовем это
lib.foo
и скажем, что ему нужен доступlib.fileA
для функцийf1
иf2
, иlib.fileB
для классаClass3
.Я включил несколько
print
звонков, чтобы проиллюстрировать, как это работает. На практике вы хотели бы удалить их (и, возможно, такжеfrom __future__ import print_function
строку).Этот конкретный пример слишком прост, чтобы показать, когда нам действительно нужно вставить запись в
sys.path
. (См ответ Ларса для случая , когда мы действительно это нужно, когда у нас есть два или более уровней пакетов каталогов, а затем мы используемos.path.dirname(os.path.dirname(__file__))
бут не очень больно и здесь.) Это также достаточно безопасно , чтобы сделать это безif _i in sys.path
тестовое задание. Однако, если каждый импортированный файл вставляет один и тот же путь - например, если обаfileA
иfileB
хотят импортировать утилиты из пакета - этоsys.path
много раз загромождает один и тот же путь, поэтому хорошо иметь егоif _i not in sys.path
в шаблоне.Идея здесь такова (и обратите внимание, что все они работают одинаково в python2.7 и python 3.x):
Если запустить как
import lib
илиfrom lib import foo
как обычный импорт пакета из обычного кода,__package
естьlib
и__name__
естьlib.foo
. Мы берем первый путь к коду, импортируем из.fileA
и т. Д.Если запустить как
python lib/foo.py
,__package__
будет None и__name__
будет__main__
.Мы берем второй путь кода.
lib
Каталог уже будет ,sys.path
так что нет необходимости добавлять его. Мы импортируем изfileA
и т. Д.Если запустить в
lib
каталоге какpython foo.py
, поведение будет таким же, как и в случае 2.При запуске в
lib
каталоге какpython -m foo
, поведение аналогично случаям 2 и 3. Однако путь кlib
каталогу отсутствуетsys.path
, поэтому мы добавляем его перед импортом. То же самое относится, если мы запустим Python, а затемimport foo
.(Поскольку
.
он включенsys.path
, нам на самом деле не нужно добавлять абсолютную версию пути сюда. Именно здесь более глубокая структура вложения пакетов, в которой мы хотим работатьfrom ..otherlib.fileC import ...
, имеет значение. Если вы этого не делаете, вы можете опустить всеsys.path
манипуляции полностью.)Ноты
Все еще есть причуды. Если вы запустите все это снаружи:
или:
поведение зависит от содержания
lib/__init__.py
. Если это существует и пусто , все хорошо:Но если
lib/__init__.py
сам импортировать,routine
чтобы он мог экспортироватьroutine.name
напрямуюlib.name
, вы получите:То есть модуль импортируется дважды, один раз через пакет, а затем снова,
__main__
чтобы он выполнял вашmain
код. Python 3.6 и позже предупреждают об этом:Предупреждение является новым, но предупредил, о поведении нет. Это часть того, что некоторые называют ловушкой двойного импорта . (Дополнительные подробности см. В выпуске 27487. ) Ник Коглан говорит:
Обратите внимание, что хотя мы нарушаем это правило здесь, мы делаем это только тогда, когда загружаемый файл не загружается как часть пакета, и наша модификация специально разработана, чтобы позволить нам получить доступ к другим файлам в этом пакете. (И, как я отметил, мы, вероятно, не должны делать этого вообще для одноуровневых пакетов.) Если мы хотим быть сверхчистыми, мы можем переписать это, например:
То есть мы модифицируем
sys.path
достаточно долго, чтобы выполнить наш импорт, а затем возвращаем его обратно в прежнее состояние (удаляем одну копию,_i
если и только если мы добавили одну копию_i
).источник
Так что, позаботившись об этом вместе со многими другими, я наткнулся на заметку, опубликованную Дорианом Б в этой статье, в которой решалась конкретная проблема, с которой я столкнулся , когда я разрабатывал модули и классы для использования с веб-сервисом, но я также хочу быть в состоянии проверить их, как я кодирую, используя средства отладчика в PyCharm. Чтобы запустить тесты в автономном классе, я бы добавил в конец файла моего класса следующее:
но если бы я хотел импортировать другие классы или модули в той же папке, то мне пришлось бы изменить все мои операторы импорта с относительной нотации на локальные ссылки (т.е. удалить точку (.)) Но после прочтения предложения Дориана я попробовал его ' one-liner ', и это сработало! Теперь я могу тестировать в PyCharm и оставлять свой тестовый код на месте, когда использую класс в другом тестируемом классе или когда я использую его в своем веб-сервисе!
Оператор if проверяет, запускаем ли мы этот модуль в качестве основного или он используется в другом модуле, который тестируется в качестве основного . Возможно, это очевидно, но я предлагаю эту заметку здесь на тот случай, если кто-то еще, разочарованный относительными проблемами импорта, может использовать ее.
источник
Вот одно решение, которое я бы не рекомендовал, но может быть полезно в некоторых ситуациях, когда модули просто не генерируются:
источник
У меня была похожая проблема, когда я не хотел изменять путь поиска модуля Python, и мне нужно было загрузить модуль относительно скрипта (несмотря на то, что «скрипты не могут импортироваться относительно всех» как BrenBarn объяснил выше).
Поэтому я использовал следующий хак. К сожалению, он полагается на
imp
модуль, который устарел с версии 3.4, и его следует отбросить в пользуimportlib
. (Возможно ли это с помощьюimportlib
тоже? Я не знаю.) Тем не менее, хак работает на данный момент.Пример доступа к членам
moduleX
insubpackage1
из скрипта, находящегося вsubpackage2
папке:Более чистый подход, по-видимому, заключается в изменении sys.path, используемого для загрузки модулей, как упомянуто Федерико.
источник
__name__
меняется в зависимости от того, выполняется ли рассматриваемый код в глобальном пространстве имен или как часть импортированного модуля.Если код не работает в глобальном пространстве,
__name__
будет имя модуля. Если он работает в глобальном пространстве имен - например, если вы набираете его в консоли или запускаете модуль как сценарий,python.exe yourscriptnamehere.py
то__name__
становится"__main__"
.Вы увидите много кода на Python с
if __name__ == '__main__'
используется для проверки того, выполняется ли код из глобального пространства имен - это позволяет вам иметь модуль, который дублируется как скрипт.Вы пытались сделать этот импорт из консоли?
источник
Ответ @ BrenBarn говорит сам за себя, но если вы похожи на меня, может потребоваться некоторое время, чтобы понять. Вот мой случай и то, как ответ @ BrenBarn относится к нему, возможно, это поможет вам.
Дело
Используя наш знакомый пример, добавьте к нему, что moduleX.py имеет относительный импорт в ..moduleA. Учитывая, что я попытался написать тестовый скрипт в каталоге subpackage1, который импортировал moduleX, но затем получил страшную ошибку, описанную OP.
Решение
Переместите тестовый скрипт на тот же уровень, что и package, и импортируйте package.subpackage1.moduleX
объяснение
Как объяснено, относительный импорт выполняется относительно текущего имени. Когда мой тестовый скрипт импортирует moduleX из той же директории, тогда имя модуля внутри moduleX - это moduleX. Когда он встречает относительный импорт, интерпретатор не может выполнить резервное копирование иерархии пакетов, потому что он уже наверху
Когда я импортирую moduleX сверху, тогда имя внутри moduleX - package.subpackage1.moduleX, и можно найти относительный импорт
источник
Написал небольшой пакет Python для PyPi, который может помочь зрителям в этом вопросе. Пакет действует как обходной путь, если вы хотите иметь возможность запускать файлы python, содержащие импорт, содержащий пакеты верхнего уровня, из пакета / проекта, не находясь непосредственно в каталоге импортируемого файла. https://pypi.org/project/import-anywhere/
источник
Чтобы Python не возвращался ко мне "Попытка относительного импорта в не-пакет". пакет /
init .py subpackage1 / init .py moduleX.py moduleY.py subpackage2 / init .py moduleZ.py moduleA.py
Эта ошибка возникает, только если вы применяете относительный импорт к родительскому файлу. Например, родительский файл уже возвращает main после того, как вы напечатали «print ( name )» в moduleA.py. Так что ЭТОТ файл уже mainон не может вернуть родительский пакет в дальнейшем. относительный импорт требуется в файлах пакетов subpackage1 и subpackage2, которые вы можете использовать ".." для ссылки на родительский каталог или модуль. Но родительский пакет - если уже пакет верхнего уровня, он не может идти дальше выше этого родительского каталога (пакета). Такие файлы, где вы применяете относительный импорт к родителям, могут работать только с приложением абсолютного импорта. Если вы будете использовать ABSOLUTE IMPORT В РОДИТЕЛЬСКОМ ПАКЕТЕ, НЕТ ОШИБКИ, поскольку python знает, кто находится на верхнем уровне пакета, даже если ваш файл находится в подпакетах из-за концепции PYTHON PATH, которая определяет верхний уровень проекта.
источник