Относительный импорт в миллиардный раз

718

Я был здесь:

и множество 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 выдает это сообщение об ошибке, что означает «не пакет», почему и как вы определяете «пакет», и точный ответ, выраженный в терминах, достаточно простых для понимания в детском саду .

Пол Руб
источник
5
Как вы пытаетесь использовать файлы, которые вы показываете? Какой код вы используете?
BrenBarn
См. Python.org/dev/peps/pep-0328 . Я использовал формат пакета, который я описал в своем посте. В INIT файлы .py пусты. moduleY.py имеет def spam(): pass, moduleA.py имеет def eggs(): pass. Я пытался выполнить пару команд «из. Что-то импортировать что-то», но они не работали. Снова смотрите pep-0328.
6
Смотри мой ответ. Вы еще не до конца прояснили, что делаете, но если вы пытаетесь сделать это from .something import somethingв интерактивном переводчике, это не сработает. Относительный импорт может использоваться только внутри модулей, но не в интерактивном режиме.
BrenBarn
105
Сам факт того, что «миллиарды» людей - на данный момент 83 136 человек - имеют достаточно проблем с импортом, чтобы найти этот вопрос; мы можем только заключить, что импорт python нелогичен для многих, если не для большинства программистов. Гвидо, возможно, тебе следует принять это и попросить комитет по редизайну механизма импорта. Как минимум, этот синтаксис должен работать, если x.py и z.py находятся в одном каталоге. А именно, если в x.py есть оператор, «из .z import MyZebraClass» x должен импортировать z ДАЖЕ, если он запускается как главный ! Почему это так сложно?
Стив Л
4
После прочтения большей части этой темы, хотя это и не ответ на вопрос, «просто используйте абсолютный импорт», кажется, решение ...
CodeJockey

Ответы:

1044

Скрипт против модуля

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

Два решения:

  1. Если вы действительно хотите запускать moduleXнапрямую, но хотите, чтобы он считался частью пакета, вы можете это сделать python -m package.subpackage1.moduleX. -mГоворит Python , чтобы загрузить его как модуль, а не как сценарий верхнего уровня.

  2. Или, возможно, вы на самом деле не хотите запускать 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.)

BrenBarn
источник
62
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х?
7
@Stopforgettingmyaccounts ...: PEP 366 показывает, как это работает. Внутри файла вы можете сделать __package__ = 'package.subpackage1'или тому подобное. Тогда только этот файл будет всегда рассматриваться как часть этого пакета , даже если работать напрямую. Если у вас есть другие вопросы о __package__вас, возможно, вы захотите задать отдельный вопрос, поскольку мы обсуждаем вопрос вашего первоначального вопроса здесь.
BrenBarn
109
Это должно быть ответом на все вопросы об относительном импорте Python. Это должно быть даже в документах.
edsioufi
10
Смотрите python.org/dev/peps/pep-0366 - «Обратите внимание, что этот шаблон достаточно, только если пакет верхнего уровня уже доступен через sys.path. Для прямого выполнения потребуется дополнительный код, который манипулирует sys.path. работать без импорта пакета верхнего уровня ". - это самый неприятный момент для меня, так как этот «дополнительный код» на самом деле довольно длинный и не может быть сохранен в другом месте в пакете для легкого запуска.
Майкл Скотт Катберт
14
Этот ответ в настоящее время отключен на несколько важных деталей, касающихся __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.
user2357112 поддерживает Monica
42

Это действительно проблема внутри Python. Истоки путаницы в том, что люди ошибочно принимают относительное значение в качестве относительного пути, а это не так.

Например, когда вы пишете в faa.py :

from .. import foo

Это имеет смысл, только если faa.py был идентифицирован и загружен python во время выполнения как часть пакета. В этом случае имя модуля для faa.py бы, например , some_packagename.faa . Если файл был загружен только потому, что он находится в текущем каталоге, когда запускается python, то его имя не будет ссылаться на какой-либо пакет, и в итоге относительный импорт завершится неудачно.

Простое решение для ссылки на модули в текущем каталоге, это использовать это:

if __package__ is None or __package__ == '':
    # uses current directory visibility
    import foo
else:
    # uses current package visibility
    from . import foo
Рами Ка.
источник
6
Правильное решение состоит в from __future__ import absolute_importтом, чтобы заставить пользователя правильно использовать ваш код ... так что вы всегда можете это сделатьfrom . import foo
Джакомо Альзетта
@ Джакомо: абсолютно правильный ответ на мою проблему. Спасибо!
Фабио
8

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

from __future__ import print_function # only when showing how this works

if __package__:
    print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
    from .fileA import f1, f2
    from .fileB import Class3
else:
    print('Not a package; __name__ is {!r}'.format(__name__))
    # these next steps should be used only with care and if needed
    # (remove the sys.path manipulation for simple cases!)
    import os, sys
    _i = os.path.dirname(os.path.abspath(__file__))
    if _i not in sys.path:
        print('inserting {!r} into sys.path'.format(_i))
        sys.path.insert(0, _i)
    else:
        print('{!r} is already in sys.path'.format(_i))
    del _i # clean up global name space

    from fileA import f1, f2
    from fileB import Class3

... all the code as usual ...

if __name__ == '__main__':
    import doctest, sys
    ret = doctest.testmod()
    sys.exit(0 if ret.failed == 0 else 1)

Идея здесь такова (и обратите внимание, что все они работают одинаково в python2.7 и python 3.x):

  1. Если запустить как import libили from lib import fooкак обычный импорт пакета из обычного кода, __packageесть libи __name__есть lib.foo. Мы берем первый путь к коду, импортируем из .fileAи т. Д.

  2. Если запустить как python lib/foo.py, __package__будет None и __name__будет __main__.

    Мы берем второй путь кода. libКаталог уже будет , sys.pathтак что нет необходимости добавлять его. Мы импортируем из fileAи т. Д.

  3. Если запустить в libкаталоге как python foo.py, поведение будет таким же, как и в случае 2.

  4. При запуске в libкаталоге как python -m foo, поведение аналогично случаям 2 и 3. Однако путь к libкаталогу отсутствует sys.path, поэтому мы добавляем его перед импортом. То же самое относится, если мы запустим Python, а затем import foo.

    (Поскольку . он включен sys.path, нам на самом деле не нужно добавлять абсолютную версию пути сюда. Именно здесь более глубокая структура вложения пакетов, в которой мы хотим работать from ..otherlib.fileC import ..., имеет значение. Если вы этого не делаете, вы можете опустить все sys.pathманипуляции полностью.)

Ноты

Все еще есть причуды. Если вы запустите все это снаружи:

$ python2 lib.foo

или:

$ python3 lib.foo

поведение зависит от содержания lib/__init__.py. Если это существует и пусто , все хорошо:

Package named 'lib'; __name__ is '__main__'

Но если lib/__init__.py сам импортировать, routineчтобы он мог экспортировать routine.nameнапрямую lib.name, вы получите:

$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'

То есть модуль импортируется дважды, один раз через пакет, а затем снова, __main__чтобы он выполнял ваш mainкод. Python 3.6 и позже предупреждают об этом:

$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'

Предупреждение является новым, но предупредил, о поведении нет. Это часть того, что некоторые называют ловушкой двойного импорта . (Дополнительные подробности см. В выпуске 27487. ) Ник Коглан говорит:

Эта следующая ловушка существует во всех текущих версиях Python, включая 3.3, и может быть кратко изложена в следующем общем руководстве: «Никогда не добавляйте каталог пакета или любой каталог внутри пакета непосредственно в путь Python».

Обратите внимание, что хотя мы нарушаем это правило здесь, мы делаем это только тогда, когда загружаемый файл не загружается как часть пакета, и наша модификация специально разработана, чтобы позволить нам получить доступ к другим файлам в этом пакете. (И, как я отметил, мы, вероятно, не должны делать этого вообще для одноуровневых пакетов.) Если мы хотим быть сверхчистыми, мы можем переписать это, например:

    import os, sys
    _i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if _i not in sys.path:
        sys.path.insert(0, _i)
    else:
        _i = None

    from sub.fileA import f1, f2
    from sub.fileB import Class3

    if _i:
        sys.path.remove(_i)
    del _i

То есть мы модифицируем sys.pathдостаточно долго, чтобы выполнить наш импорт, а затем возвращаем его обратно в прежнее состояние (удаляем одну копию, _iесли и только если мы добавили одну копию _i).

Торек
источник
7

Так что, позаботившись об этом вместе со многими другими, я наткнулся на заметку, опубликованную Дорианом Б в этой статье, в которой решалась конкретная проблема, с которой я столкнулся , когда я разрабатывал модули и классы для использования с веб-сервисом, но я также хочу быть в состоянии проверить их, как я кодирую, используя средства отладчика в PyCharm. Чтобы запустить тесты в автономном классе, я бы добавил в конец файла моего класса следующее:

if __name__ == '__main__':
   # run test code here...

но если бы я хотел импортировать другие классы или модули в той же папке, то мне пришлось бы изменить все мои операторы импорта с относительной нотации на локальные ссылки (т.е. удалить точку (.)) Но после прочтения предложения Дориана я попробовал его ' one-liner ', и это сработало! Теперь я могу тестировать в PyCharm и оставлять свой тестовый код на месте, когда использую класс в другом тестируемом классе или когда я использую его в своем веб-сервисе!

# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
    from codex import Codex # these are in same folder as module under test!
    from dblogger import DbLogger
else:
    from .codex import Codex
    from .dblogger import DbLogger

Оператор if проверяет, запускаем ли мы этот модуль в качестве основного или он используется в другом модуле, который тестируется в качестве основного . Возможно, это очевидно, но я предлагаю эту заметку здесь на тот случай, если кто-то еще, разочарованный относительными проблемами импорта, может использовать ее.

Стив Л
источник
1
Это на самом деле решает это. Но это действительно противно. Почему это не поведение по умолчанию ?!
Ло Толменкре
4

Вот одно решение, которое я бы не рекомендовал, но может быть полезно в некоторых ситуациях, когда модули просто не генерируются:

import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()
Federico
источник
2

У меня была похожая проблема, когда я не хотел изменять путь поиска модуля Python, и мне нужно было загрузить модуль относительно скрипта (несмотря на то, что «скрипты не могут импортироваться относительно всех» как BrenBarn объяснил выше).

Поэтому я использовал следующий хак. К сожалению, он полагается на impмодуль, который устарел с версии 3.4, и его следует отбросить в пользу importlib. (Возможно ли это с помощью importlibтоже? Я не знаю.) Тем не менее, хак работает на данный момент.

Пример доступа к членам moduleXin subpackage1из скрипта, находящегося в subpackage2папке:

#!/usr/bin/env python3

import inspect
import imp
import os

def get_script_dir(follow_symlinks=True):
    """
    Return directory of code defining this very function.
    Should work from a module as well as from a script.
    """
    script_path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        script_path = os.path.realpath(script_path)
    return os.path.dirname(script_path)

# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)

# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST

Более чистый подход, по-видимому, заключается в изменении sys.path, используемого для загрузки модулей, как упомянуто Федерико.

#!/usr/bin/env python3

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    # __file__ should be defined in this case
    PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
   sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *
Lars
источник
Это выглядит лучше ... Жаль, что все еще требует, чтобы вы вставили имя родительского каталога в файл ... возможно, это можно улучшить с помощью importlib. Может быть, importlib может быть даже пропатчен, чтобы относительный импорт «просто работал» для простых случаев использования. Я возьму трещину в этом.
Эндрю Вагнер,
Я использую Python 2.7.14, хотя. Будет ли что-то подобное еще работать?
user3474042
Я только что протестировал оба подхода на Python 2.7.10, и они работали хорошо для меня. На самом деле, у вас нет проблемы устаревшего модуля imp в 2.7, так что тем лучше.
Ларс
2

__name__ меняется в зависимости от того, выполняется ли рассматриваемый код в глобальном пространстве имен или как часть импортированного модуля.

Если код не работает в глобальном пространстве, __name__будет имя модуля. Если он работает в глобальном пространстве имен - например, если вы набираете его в консоли или запускаете модуль как сценарий, python.exe yourscriptnamehere.pyто __name__становится"__main__" .

Вы увидите много кода на Python с if __name__ == '__main__' используется для проверки того, выполняется ли код из глобального пространства имен - это позволяет вам иметь модуль, который дублируется как скрипт.

Вы пытались сделать этот импорт из консоли?

theodox
источник
Ах, так вы упоминаете -m. Это заставляет ваш модуль работать как скрипт - если вы вставите туда if __name__ == '__main__', вы должны увидеть, что это '__main__' из-за -m. Попробуйте просто импортировать свой модуль в другой модуль, чтобы он не был на верхнем уровне ... который должен позволить вам выполнить относительный импорт
theodox
Я попытался выполнить этот импорт из консоли, с активным файлом, являющимся правильным модулем.
@Stopforgettingmyaccounts ...: Что вы подразумеваете под "активным файлом"?
BrenBarn
Я использую Pyscripter. Я был в moduleX.py, когда запустил импорт: из .moduleY импорта спама и из. импортировать ModuleY.
Не импортировать .moduleY, за которым следует moduleY.spam ()?
Теодокс
2

Ответ @ BrenBarn говорит сам за себя, но если вы похожи на меня, может потребоваться некоторое время, чтобы понять. Вот мой случай и то, как ответ @ BrenBarn относится к нему, возможно, это поможет вам.

Дело

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

Используя наш знакомый пример, добавьте к нему, что moduleX.py имеет относительный импорт в ..moduleA. Учитывая, что я попытался написать тестовый скрипт в каталоге subpackage1, который импортировал moduleX, но затем получил страшную ошибку, описанную OP.

Решение

Переместите тестовый скрипт на тот же уровень, что и package, и импортируйте package.subpackage1.moduleX

объяснение

Как объяснено, относительный импорт выполняется относительно текущего имени. Когда мой тестовый скрипт импортирует moduleX из той же директории, тогда имя модуля внутри moduleX - это moduleX. Когда он встречает относительный импорт, интерпретатор не может выполнить резервное копирование иерархии пакетов, потому что он уже наверху

Когда я импортирую moduleX сверху, тогда имя внутри moduleX - package.subpackage1.moduleX, и можно найти относительный импорт

Брэд Дре
источник
Надеюсь, вы можете направить меня в этом. В следующей ссылке, если вы перейдете к случаю 3, он говорит, что решение 1 невозможно. Пожалуйста, вы можете проверить это и дать мне знать. Это мне очень поможет. chrisyeh96.github.io/2017/08/08/…
переменная
@variable есть опечатка в ссылке, и мне не разрешено редактировать. Посмотрел на случай 3 и не следовал точно, что вы получаете. Когда я попробовал этот пример в python 2, не было никаких проблем, из-за которых я думал, что что-то пропустил. Возможно, вам следует опубликовать новый вопрос, но вам нужно привести более четкий пример. Случай 4 затрагивает то, о чем я говорю, в моем ответе: вы не можете перейти к каталогу для относительного импорта, ЕСЛИ интерпретатор не запускается в родительском каталоге
Брэд Дре
Спасибо, я имею в виду Python 3 и здесь вопрос stackoverflow.com/questions/58577767/…
переменная
1

Относительный импорт использует атрибут имени модуля для определения позиции этого модуля в иерархии пакетов. Если имя модуля не содержит никакой информации о пакете (например, для него установлено значение «main»), то относительный импорт разрешается так, как если бы модуль был модулем верхнего уровня, независимо от того, где этот модуль фактически расположен в файловой системе.

Написал небольшой пакет Python для PyPi, который может помочь зрителям в этом вопросе. Пакет действует как обходной путь, если вы хотите иметь возможность запускать файлы python, содержащие импорт, содержащий пакеты верхнего уровня, из пакета / проекта, не находясь непосредственно в каталоге импортируемого файла. https://pypi.org/project/import-anywhere/

ec2604
источник
-2

Чтобы 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, которая определяет верхний уровень проекта.

Сакши Джайн
источник