首先讓我們先從如何在python from import
工作:
那麼首先讓我們來看看字節碼:
>>> 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
,然後他從框架棧中彈出這是執行的最後一個操作碼這是IMPORT_NAME
的返回值v
,然後調用函數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()
函數很安靜,它首先嚐試從模塊v
中獲取屬性name
,如果它不存在,則會引發ImportError
,否則返回此屬性。
現在這與相對導入有什麼關係?
好像from . import b
這樣的相對導入例如在OP問題到from pkg import b
的情況下是等價的。
但這是怎麼發生的?爲了理解這一點,我們應該看看Python的import.c
模塊,特別是函數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
前什麼只是發生?
前)在pkg/b.py
from . import a
被調用時,上面from pkg import a
,這又是在字節碼解釋爲被翻譯相當於import pkg; getattr(pkg, 'a')
。但是等一下a
是個模塊嗎?! 好吧,這裏有趣的部分,如果我們有像from module|package import module
在這種情況下會發生第二次導入,這是導入子句中模塊的導入。因此,在OP示例中,我們現在需要導入pkg/a.py
,正如您首先知道的,我們在我們的sys.modules
中設置了一個新模塊的密鑰,該模塊將爲pkg.a
,然後我們繼續解釋模塊pkg/a.py
,但在模塊pkg/a.py
完成導入,請致電from . import b
。
現在來到了二)部分,pkg/b.py
將被導入,並在其中打開它會首先嚐試import pkg
這是因爲pkg
已經導入所以我們sys.modules
關鍵pkg
它只會返回該值鍵。然後將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')
,這將在import_from()
函數中產生AttributeError
,該函數將被翻譯爲ImportError(cannot import name a)
。
免責聲明:這是我自己努力去理解口譯員內部發生的事情,我遠不是專家。
編輯:這個答案改寫,因爲當我試着看了一遍我說我的答案是如何制定不好,現在希望這將是更爲有用:)
您可以指定您在更改爲from時收到的'ImportError'的詳細信息。進口b'? – 2011-06-15 01:03:44
你如何練習這段代碼?你有'pkg'中的另外一個模塊,它的功能如下:'if __name__ =='main':from。導入一個'? 如果是這樣,您可能需要閱讀[PEP 366](http://python.org/dev/peps/pep-0366/),這個PEP可以更容易地使用包中的可執行模塊的相對導入。 – 2011-06-15 01:09:03
如果__a__依賴於__b__,而__b__依賴於__a__,爲什麼不加入同一個文件? – JBernardo 2011-06-15 01:14:21