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
をしますか?
彼が見つけたときに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
、最後に実行されたオペコードの戻り値である値をポップし、次の2つの引数を使用し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__
ます。これも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__._
うーん、直前に何が起こったのImportError
?
最初に) from . import a
がpkg/b.py
呼び出されます。これは、上記で説明したようにに変換されます。from pkg import a
これもバイトコードで、と同等import pkg; getattr(pkg, 'a')
です。しかし、ちょっと待ってくださいa
モジュールでもありますか?!from module|package import module
この場合、import句のモジュールのインポートである2番目のインポートが発生するようなものがある場合は、ここで楽しい部分があります。したがって、OPの例でも、インポートする必要がありpkg/a.py
ます。最初にsys.modules
、新しいモジュールのキーを設定しpkg.a
、次にモジュールの解釈を続行しますが、モジュールのインポートが完了pkg/a.py
する前に、を呼び出します。 。pkg/a.py
from . import b
次に、2番目の部分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:この答えは言い換えられました。もう一度読み込もうとしたときに、自分の答えがどのように定式化されていなかったかを指摘したからです。