Сначала давайте начнем с того, как 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
хм, интересно :), поэтому from foo import bar
переводится сначала IMPORT_NAME foo
, что эквивалентно import foo
, а затем IMPORT_FROM bar
.
Что теперь IMPORT_FROM
делает?
посмотрим, что сделает питон, когда найдет 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
, иначе вернет этот атрибут.
Какое отношение это имеет к относительному импорту?
Хорошо относительный импорт, такой как from . import b
, эквивалентен, например, в случае, который в вопросе OP, к from pkg import b
.
Но как это случилось? Чтобы понять это, мы должны взглянуть на модуль import.c
модуля python специально на функцию get_parent () . Как вы видите, функция довольно длинная, чтобы перечислять ее здесь, но в целом, когда она видит относительный импорт, она пытается заменить точку .
родительским пакетом, в зависимости от модуля __main__
, который снова из ОП вопрос это пакет pkg
.
Теперь давайте соберем все это вместе и попытаемся выяснить, почему мы в конечном итоге получаем поведение в вопросе ОП.
В этом нам поможет, если мы увидим, что 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__._
хмм, что только что произошло до 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
.
Теперь перейдем к части Second) , 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: Этот ответ был перефразирован, потому что, когда я попытался прочитать его снова, я заметил, как мой ответ был сформулирован неверно, надеюсь, теперь он будет более полезным :)