由 import_module 加载时从模块引用 python 文件

Referencing a python file from a module when loaded by import_module

我想使用 import_module 从 importlib 导入一个模块。当我这样做时,找不到我从我的模块引用的文件。如果我从 python shell(不使用 main.py)正常导入我的模块,它会按预期工作。另外,如果我将 MyModule.py 的路径添加到 sys.path 它可以工作,但据我了解我不应该这样做(在下面的代码中注释掉)。

如何在 import_module 加载模块时也加载我的引用文件?

我有以下文件结构

main.py
  subfolders
    folder1
      __init__.py
      MyModule.py
      hello.py

main.py

的内容
from importlib import import_module

modulename = 'subfolders.folder1.MyModule'
print("Import module ", modulename)
module = import_module(modulename)
m_instance = module.MyModule()

m_instance.module_hello()

MyModule.py

的内容
#This is the solution that works but feels wrong
#import os, sys
#sys.path.append(os.path.dirname(__file__))

from hello import hello_world

class MyModule(object):
    def __init__(self):
        print("Init MyModule")

    def module_hello(self):
        hello_world()

hello.py

的内容
def hello_world():
    print("Hello World!")

当我 运行 我得到:

c:\git\PythonImportTest>python main.py
Import module  subfolders.folder1.MyModule
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    module = import_module(modulename)
  File "C:\Miniconda3\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 665, in exec_module
  File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
  File "c:\git\PythonImportTest\subfolders\folder1\MyModule.py", line 5, in <module>
    from hello import hello_world
ImportError: No module named 'hello'

首先,您需要通过在其中放置一个空 __init__.py 来使您的 subfolders 目录成为一个包。其次,您需要通过绝对导入或相对导入来导入 hello 模块。

绝对导入:

from subfolders.folder1.hello import hello_world

相对导入:

from .hello import hello_world

你现在的做法是在你的顶级包中寻找 hello.py(你的 main.py 所在的位置)。因为在那里找不到它,所以你会得到一个错误。

关于 Python3

中相对导入的说明

你可能从 Python2 切换到 Python3 这就是为什么你在使用隐式相对导入时遇到麻烦的原因。正如 PEP404 所说:

In Python 3, implicit relative imports within packages are no longer available - only absolute imports and explicit relative imports are supported. In addition, star imports (e.g. from x import * ) are only permitted in module level code.

意味着您的代码应该适用于 Python2,但对于 Python3,您必须使用上述选项之一。另见:Changes in import statement python3

您的代码存在的问题是子文件夹是文件夹而不是包。如果您使用 import_module,则只能在包中搜索子包。

解决方法: 在您的子文件夹中创建一个 init.py 并在那里导入 folder1。