Python の __import__ に fromlist が必要なのはなぜですか? 質問する

Python の __import__ に fromlist が必要なのはなぜですか? 質問する

Python では、プログラムでモジュールをインポートする場合は、次のようにします。

module = __import__('module_name')

サブモジュールをインポートしたい場合、次のようにすれば簡単にできると思います。

module = __import__('module_name.submodule')

もちろん、これは機能しません。module_nameもう一度取得するだけです。次の操作を行う必要があります。

module = __import__('module_name.submodule', fromlist=['blah'])

なぜ?の実際の値はfromlist、空でない限り、まったく問題にならないようです。引数を要求して、その値を無視することにはどのような意味があるのでしょうか?

Python のほとんどの処理は正当な理由があって行われているようですが、この動作が存在する理由について、私にはどうしても合理的な説明が思いつきません。

ベストアンサー1

実際、 の振る舞いは、を呼び出すステートメント__import__()の実装に完全に起因します。 は基本的に、によって呼び出される5 つのわずかに異なる方法(2 つの主なカテゴリ) があります。import__import__()__import__()import

import pkg
import pkg.mod
from pkg import mod, mod2
from pkg.mod import func, func2
from pkg.mod import submod

最初にそして2 番目のケースでは、importステートメントは「最も左の」モジュール オブジェクトを「最も左の」名前 に割り当てる必要があります。pkgステートメントによってローカル名 が導入されたため、属性を持つモジュール オブジェクトをimport pkg.mod実行できます。したがって、関数は「最も左の」モジュール オブジェクトを返して、 に割り当てる必要があります。したがって、これら 2 つのインポート ステートメントは次のように変換されます。pkg.mod.func()importpkgmod__import__()pkg

pkg = __import__('pkg')
pkg = __import__('pkg.mod')

3 番目、4 番目、および 5 番目のケースでは、importステートメントはより多くの作業を行う必要があります。つまり、(潜在的に) 複数の名前を割り当てる必要があり、その__import__()名前はモジュール オブジェクトから取得する必要があります。関数は 1 つのオブジェクトのみを返すことができ、モジュール オブジェクトからそれらの名前をそれぞれ取得させる理由はありません (また、実装がはるかに複雑になります)。したがって、単純なアプローチは次のようになります (3 番目のケースの場合)。

tmp = __import__('pkg')
mod = tmp.mod
mod2 = tmp.mod2

pkgただし、がパッケージであり、modまたはmod2そのパッケージ内のモジュールである場合は機能しません。まだ輸入されていないもの3 番目と 5 番目のケースと同様に、関数はとがステートメントでアクセス可能な名前である__import__()ことを知っておく必要があります。そうすることで、関数はそれらがモジュールであるかどうかを確認し、それらもインポートしようとすることができます。そのため、呼び出しは次のようになります。modmod2import

tmp = __import__('pkg', fromlist=['mod', 'mod2'])
mod = tmp.mod
mod2 = tmp.mod2

これにより、 はおよび との__import__()ロードを試行します(ただし、またはが存在しない場合は、呼び出しでエラーにはなりません。エラーの生成はステートメントに委ねられます)。ただし、これは 4 番目と 5 番目の例には依然として適切ではありません。呼び出しが次のようになると、pkg.modpkg.mod2pkgmodmod2__import__()import

tmp = __import__('pkg.mod', fromlist=['submod'])
submod = tmp.submod

すると、以前と同じように になり、属性を取得したいモジュールではなくtmpなります。実装では、関数が既に行っているようにパッケージ名を に分割して名前を走査するなど、ステートメントが余分な作業を行うようにすることもできましたが、これは労力の一部を重複させることを意味していました。そのため、代わりに実装ではを返すようにしました。pkgpkg.modsubmodimport.__import__()__import__()一番右モジュールの代わりに左端1つもし、もし、fromlist が渡され、空ではありません。

( およびimport pkg as p構文from pkg import mod as mは、どのローカル名が割り当てられるかを除いて、このストーリーについては何も変更しません。が使用され__import__()ても関数は何も変更せずas、すべてimportステートメントの実装に残ります。)

おすすめ記事