私はpython3(3.6)でimportlib
を使おうとしています。
ディレクトリ構造
main.py
_#Note: I will only modify line 4 that uses importlib
import importlib
if __name__ == '__main__':
print("In main.py")
hello = importlib.import_module('hello', package='./')
print("Loaded hello.py")
hello.hello()
_
hello.py
_def hello():
print('Hello world')
_
folder/hello.py
_def hello():
print('Hello world in folder')
_
観察
私が行った場合
hello = importlib.import_module('hello', package='./')
または
hello = importlib.import_module('hello')
ルートフォルダからhello.pyをインポートし、_hello world
_を出力します。
私が行った場合
hello = importlib.import_module('folder.hello')
ルートフォルダからfolder/hello.pyをインポートし、_hello world in folder
_を出力します。
しかし、私がそうするなら
hello = importlib.import_module('hello', package='folder')
または
hello = importlib.import_module('hello', package='./folder')
エラーが発生します
_Traceback (most recent call last):
File "main.py", line 4, in <module>
hello = importlib.import_module('hello', package='./folder')
File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'hello'
_
問題
ここで何が起こっているのかわかりません。 pythonモジュールとパッケージの理解に何か問題があると確信しています。これが予期される動作である理由を誰かが説明できますか?
インポートされるモジュールの最初の引数が絶対モジュール参照(先頭に.
がない)の場合、seond引数は完全に無視されます。
モジュールa
を別のモジュールb
と比較してインポートするには、次を使用する必要があります
a = importlib.import_module('.a', package='b')
あなたの場合、これはうまくいくはずです
hello = importlib.import_module('.hello', package='folder')
経験則として、2番目の引数としてpackage
を使用する場合は、import package
が機能するはずです。
from package import module
その後、
importlib.import_module(module, package)
@Maheshの答えは100%正確で正確ですが、理解を深めるために1レベル深くする必要があると思います。
以下は_import_module
_のコードです
_def import_module(name, package=None):
"""Import a module.
The 'package' argument is required when performing a relative import. It
specifies the package to use as the anchor point from which to resolve the
relative import to an absolute import.
"""
level = 0
if name.startswith('.'):
if not package:
msg = ("the 'package' argument is required to perform a relative "
"import for {!r}")
raise TypeError(msg.format(name))
for character in name:
if character != '.':
break
level += 1
return _bootstrap._gcd_import(name[level:], package, level)
_
name
が_.
_で始まらない場合は、if
部分が実行されないことがわかります。 _level=0
_を値として実行されるreturn _bootstrap._gcd_import(name[level:], package, level)
があります
それでは、以下のコードを持つ関数に取り掛かりましょう。
_def _gcd_import(name, package=None, level=0):
"""Import and return the module based on its name, the package the call is
being made from, and the level adjustment.
This function represents the greatest common denominator of functionality
between import_module and __import__. This includes setting __package__ if
the loader did not.
"""
_sanity_check(name, package, level)
if level > 0:
name = _resolve_name(name, package, level)
return _find_and_load(name, _gcd_import)
_
ここでも、_find_and_load(name, _gcd_import)
を実行するだけです。これは、level
が前のコードの_0
_であるため、package
パラメーターが渡されたり使用されたりすることはありません。 __find_and_load
_メソッド。これで、以下を実行してこれを簡単に確認できます
_import importlib
hello = importlib.import_module('hello', package='IAmNotAfolder')
hello.hello()
_
そして、ベース_Hello World
_から_hello.py
_を出力します
ご覧のとおり、名前が相対インポート用の_.
_で始まらない場合、package
パラメーターはまったく使用されません。これが、パッケージの内容に関係なく、ベースフォルダーから_No module named 'hello'
_をインポートしようとしているため、エラー_hello.py
_が発生する理由です。
この回答により、舞台裏で何が起こっているのかを理解しやすくなることを願っています