Ответ 1
Сначала начнем с того, как from import
работает в python:
Хорошо сначала посмотрим на байтовый код:
>>> def foo():
... from foo import bar
>>> dis.dis(foo)
2 0 LOAD_CONST 1 (-1)
3 LOAD_CONST 2 (('bar',))
6 IMPORT_NAME 0 (foo)
9 IMPORT_FROM 1 (bar)
12 STORE_FAST 0 (bar)
15 POP_TOP
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
hmm интересно:), поэтому from foo import bar
переводится на первый IMPORT_NAME foo
, который эквивалентен import foo
, а затем IMPORT_FROM bar
.
Теперь, что IMPORT_FROM
do?
посмотрим, что делает python, когда он нашел IMPORT_FROM
:
TARGET(IMPORT_FROM)
w = GETITEM(names, oparg);
v = TOP();
READ_TIMESTAMP(intr0);
x = import_from(v, w);
READ_TIMESTAMP(intr1);
PUSH(x);
if (x != NULL) DISPATCH();
break;
Ну, в основном он получает имена для импорта из, что в нашей foo()
функции будет bar
, затем он выталкивает из стека фрейма значение v
, которое является возвратом последнего выполненного кода операции который является IMPORT_NAME
, затем вызовите функцию import_from()
с этими двумя аргументами:
static PyObject *
import_from(PyObject *v, PyObject *name)
{
PyObject *x;
x = PyObject_GetAttr(v, name);
if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Format(PyExc_ImportError, "cannot import name %S", name);
}
return x;
}
Как вы можете видеть, функция import_from()
очень тихая, сначала попробуйте получить атрибут name
из модуля v
, если он не существует, он поднимет ImportError
else вернуть этот атрибут.
Теперь, что это связано с относительным импортом?
Хороший относительный импорт, такой как from . import b
, эквивалентен, например, в случае, когда вопрос OP равен from pkg import b
.
Но как это происходит? Чтобы понять это, мы должны обратить внимание на import.c
модуль python специально для функции get_parent(). Поскольку вы видите, что функция очень тихая, чтобы перечислить здесь, но в целом то, что она делает, когда видит относительный импорт, - это попытаться заменить точку .
родительским пакетом в зависимости от модуля __main__
, который снова из Вопрос OP - это пакет pkg
.
Теперь давайте все вместе и попытаемся выяснить, почему мы закончили поведение в вопросе OP.
Для этого это поможет нам, если мы сможем увидеть, что делает python при импорте, так что наш счастливый день python уже пришел с этой функцией, которую можно включить, запустив его в дополнительном подробном режиме -vv
.
Итак, используя командную строку: python -vv -c 'import pkg.b'
:
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import pkg # directory pkg
# trying pkg/__init__.so
# trying pkg/__init__module.so
# trying pkg/__init__.py
# pkg/__init__.pyc matches pkg/__init__.py
import pkg # precompiled from pkg/__init__.pyc
# trying pkg/b.so
# trying pkg/bmodule.so
# trying pkg/b.py
# pkg/b.pyc matches pkg/b.py
import pkg.b # precompiled from pkg/b.pyc
# trying pkg/a.so
# trying pkg/amodule.so
# trying pkg/a.py
# pkg/a.pyc matches pkg/a.py
import pkg.a # precompiled from pkg/a.pyc
# clear[2] __name__
# clear[2] __file__
# clear[2] __package__
# clear[2] __name__
# clear[2] __file__
# clear[2] __package__
...
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "pkg/b.py", line 1, in <module>
from . import a
File "pkg/a.py", line 2, in <module>
from . import a
ImportError: cannot import name a
# clear __builtin__._
hmm, что только что произошло до ImportError
?
Сначала) from . import a
в pkg/b.py
, который переводится, как описано выше, в from pkg import a
, который снова в байт-коде эквивалентен import pkg; getattr(pkg, 'a')
. Но подождите минуту a
тоже модуль!
Ну вот пришла интересная часть, если у нас есть что-то вроде from module|package import module
, в этом случае произойдет второй импорт, который является импортом модуля в предложении import. Итак, снова в примере OP нам нужно теперь импортировать pkg/a.py
, и, как вы знаете, в нашем sys.modules
мы добавили ключ для нашего нового модуля, который будет pkg.a
, а затем продолжим нашу интерпретацию модуля pkg/a.py
, но перед тем, как модуль pkg/a.py
завершит импорт, вызовите from . import b
.
Теперь придет Вторая) часть, pkg/b.py
будет импортирована, и в этом случае она сначала попытается выполнить import pkg
, потому что pkg
уже импортирован, поэтому есть ключ pkg
в нашем sys.modules
он просто вернет значение этого ключа. Затем он import b
установит ключ pkg.b
в sys.modules
и начнет интерпретацию. И мы приходим к этой строке from . import a
!
Но помните pkg/a.py
уже импортировано, что означает ('pkg.a' in sys.modules) == True
, поэтому импорт будет пропущен, и будет вызван только getattr(pkg, 'a')
, но что произойдет? python не завершил импорт pkg/a.py
!? Таким образом, будет вызываться только getattr(pkg, 'a')
, и это поднимет AttributeError
в функции import_from()
, которая будет переведена на ImportError(cannot import name a)
.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Это мое личное усилие, чтобы понять, что происходит внутри интерпретатора, я далеко не эксперт.
EDIt: Этот ответ был перефразирован, потому что, когда я пытался его прочитать, я заметил, как мой ответ был плохо сформулирован, надеюсь, теперь он будет более полезен:)