80

Pythonでは、プログラムでモジュールをインポートする場合は、次の操作を実行できます。

module = __import__('module_name')

サブモジュールをインポートする場合は、次のような単純な問題だと思います。

module = __import__('module_name.submodule')

もちろん、これは機能しません。あなたはただmodule_name再び得る。あなたはしなければならない:

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

なんで?fromlist空でない限り、の実際の値はまったく重要ではないようです。引数を要求し、その値を無視することのポイントは何ですか?

Pythonのほとんどの作業は正当な理由で行われているようですが、私の人生では、この動作が存在するための合理的な説明を思い付くことができません。

4

3 に答える 3

134

実際、の動作__import__()は完全にimport、を呼び出すステートメントの実装によるもの__import__()です。基本的に、5つのわずかに異なる方法__import__()で呼び出すことができますimport(2つの主要なカテゴリがあります)。

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

1番目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__()、ロードが試行pkg.modpkg.mod2れますpkg(ただし、存在するかどうかは、呼び出しのエラーではありませんmod。エラーの生成はステートメントに任されます)。しかし、それでも4番目のおよび5番目の例、呼び出しがそうだった場合:mod2__import__()import

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

その場合、前と同じように、属性を取得するモジュールではなく、tmp最終的になります。実装は、ステートメントが余分な作業を行い、関数がすでに行っているようにパッケージ名を分割して名前をトラバースするようにすることを決定できたかもしれませんが、これは作業の一部を複製することを意味します。したがって、代わりに、実装は、 fromlistが渡され、空でない場合にのみ、左端のモジュールではなく右端のモジュールを返します。pkgpkg.modsubmodimport.__import__()__import__()

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

于 2010-04-27T22:39:46.583 に答える
7

答えを読んだときはまだ違和感があるので、以下のコードサンプルを試してみました。

まず、以下のファイル構造を構築してみてください。

tmpdir
  |A
     |__init__.py
     | B.py
     | C.py

ここで、Aはpackage、、BまたははCですmodule。したがって、ipythonで次のようなコードを試すと、次のようになります。

次に、サンプルコードをipythonで実行します。

  In [2]: kk = __import__('A',fromlist=['B'])

  In [3]: dir(kk)
  Out[3]: 
  ['B',
   '__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   '__path__']

fromlistは期待どおりに機能しているようです。しかし、で同じことをしようとすると、物事は有線になりmoduleます。C.pyというモジュールがあり、その中にコードがあるとします。

  handlers = {}

  def hello():
      print "hello"

  test_list = []

だから今、私たちはそれに同じことをしようとします。

  In [1]: ls
  C.py

  In [2]: kk = __import__('C')

  In [3]: dir(kk)
  Out[3]: 
  ['__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   'handlers',
   'hello',
   'test_list']

では、test_listをインポートしたいだけの場合、それは機能しますか?

  In [1]: kk = __import__('C',fromlist=['test_list'])

  In [2]: dir(kk)
  Out[2]: 
  ['__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   'handlers',
   'hello',
   'test_list']

結果が示すように、moduleではなくfromlistを使用しようとすると、コンパイルされているpackageため、fromlistパラメーターはまったく役に立ちません。module一度インポートすると、他のものを無視する方法はありません。

于 2013-04-10T03:15:12.873 に答える
4

答えは、次のドキュメントにあります__import__

fromlistは、エミュレートする名前のリストfrom name import ...、またはエミュレートする空のリストである必要がありimport nameます。

パッケージからモジュールをインポートする__import__('A.B', ...)場合、fromlistが空の場合はパッケージAを返しますが、fromlistが空でない場合はそのサブモジュールBを返すことに注意してください。

つまり、基本的には、これが実装の仕組みです。サブモジュールが必要な場合は、サブモジュールからインポートするものを含むものを__import__渡し、実装は、サブモジュールが返されるようなものを渡します。fromlist__import__

詳細説明

最も関連性の高いモジュールが返されるようにセマンティクスが存在すると思います。つまり、関数を持つfooモジュールを含むパッケージがあるとします。もし私が:barbaz

import foo.bar

それから私baz

foo.bar.baz()

これはのようなもの__import__("foo.bar", fromlist=[])です。

代わりに私がインポートする場合:

from foo import bar

それから私はbazbar.baz()と呼びます

これはに似てい__imoort__("foo.bar", fromlist=["something"])ます。

私が行った場合:

from foo.bar import baz

それから私baz

baz()

これはのようなもの__import__("foo.bar", fromlist=["baz"])です。

したがって、最初のケースでは、完全修飾名を使用する必要があります。したがって__import__、インポートされた要素を参照するために使用する最初のモジュール名、つまりを返しますfoo。最後のケースでは、はインポートされた要素を含む最も具体的なモジュールであるため、モジュールを返すbarことは理にかなっています。__import__foo.bar

from <package> import <module>2番目のケースは少し奇妙ですが、構文を使用したモジュールのインポートをサポートするように記述されていると思います。その場合barでも、返される最も具体的なモジュールです。

于 2010-04-27T19:20:31.010 に答える