如何使用 python importlib 从相对路径动态 import_module
How to dynamically import_module from a relative path with python importlib
我的文件夹结构如下:
__init__.py
core/
fields.py
managers.py
models.py
__init__.py
models/
products.py
suppliers.py
__init__.py
From class A in fields.py
我正在尝试加载 class Supplier using importlib.load_module
from which is defined in products.py or suppliers.py.这需要填充一些配置以生成一些 sql.
下面的方法生成 TypeError: the 'package' argument is required to perform a relative import for '..models.suppliers.Supplier''
。我不确定如何定义包,因为这不是已安装的包。
import importlib
model_name = "Supplier"
path = f"...models.{model_name.lower()}s.{model_name}"
model = importlib.import_module(path)
为了尝试解决这个问题,我尝试了如下所示的各种组合,但均无济于事。错误 ModuleNotFoundError: No module named '.core'
或 ModuleNotFoundError: No module named '.models'
取决于 .. 我正在使用的组合。
import importlib
model_name = "Supplier"
path = f"...models.{model_name.lower()}s.{model_name}"
model = importlib.import_module(path, package=".core.fields")
path = f"{model_name.lower()}s"
model = importlib.import_module(path, package="..models")
也不起作用 - 但简单地导入 from ..models import Supplier
可以。
我也尝试让 python 使用绝对路径。但是通过使用这种方法,错误变为:ImportError: attempted relative import with no known parent package
(参考suppliers.py中的导入)。
在这种情况下,suppliers.py 中使用的相对导入似乎失败了。请参阅下面的示例。
from importlib.machinery import SourceFileLoader
from pathlib import Path
import os
model_name = "Supplier"
parent_path = Path(__file__).resolve().parent.parent
module_path = os.path.join(parent_path, 'models', f'{model_name.lower()}s.py')
Model = getattr(SourceFileLoader(model, module_path).load_module(), model_name)
编辑:为了完整起见,抛出 ModuleNotFoundError: No module named '.'
。所以也不行。
model = __import__(f"..models.{model.lower()}.{model}")
我错过了什么?
以下是文档中有关如何在给定文件路径的情况下加载模块的方法:
https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
...
import importlib
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
不使用路径库:
(我保留这个是因为文件名操作和目录处理的例子可能仍然需要,即使按照上面的方法)
的确,在给定 Python 中的 file-path 的情况下,导入文件的正确方法很复杂。无需搜索其他食谱,这里有一种方法
临时修补 sys.path,并调用普通 __import__
从指定的目录
获取文件
(Python 文件的路径应使用文件系统符号给出:/
分隔符,而不是 .
。不过,此代码将忽略文件扩展名)
import sys
from pathlib import Path
def importpath(path):
strpath = str(path)
if not strpath.startswith("/"):
parent_path = Path(sys._getframe().f_globals.get("__file__", ".")).parent
path = parent_path / path
else:
path = Path(path)
try:
sys.path.insert(0, str(path.parent))
module = __import__(path.stem)
finally:
sys.path.pop(0)
return module
但是,此代码会将给定文件作为单独的 Python 模块导入,而不知道它应该在哪个包中。这意味着如果该模块中有任何相关导入,它们将失败.
阅读更多内容后,发现解决方案就在眼前。
您可以使用 getattr
而不是尝试使用 importlib 做有趣的事情
def find_my_class(class_name):
from .. import models as configuration_models
module = getattr(configuration_models, f"{class_name.lower()}s")
return getattr(module, class_name)
我的文件夹结构如下:
__init__.py
core/
fields.py
managers.py
models.py
__init__.py
models/
products.py
suppliers.py
__init__.py
From class A in fields.py
我正在尝试加载 class Supplier using importlib.load_module
from which is defined in products.py or suppliers.py.这需要填充一些配置以生成一些 sql.
下面的方法生成 TypeError: the 'package' argument is required to perform a relative import for '..models.suppliers.Supplier''
。我不确定如何定义包,因为这不是已安装的包。
import importlib
model_name = "Supplier"
path = f"...models.{model_name.lower()}s.{model_name}"
model = importlib.import_module(path)
为了尝试解决这个问题,我尝试了如下所示的各种组合,但均无济于事。错误 ModuleNotFoundError: No module named '.core'
或 ModuleNotFoundError: No module named '.models'
取决于 .. 我正在使用的组合。
import importlib
model_name = "Supplier"
path = f"...models.{model_name.lower()}s.{model_name}"
model = importlib.import_module(path, package=".core.fields")
path = f"{model_name.lower()}s"
model = importlib.import_module(path, package="..models")
也不起作用 - 但简单地导入 from ..models import Supplier
可以。
我也尝试让 python 使用绝对路径。但是通过使用这种方法,错误变为:ImportError: attempted relative import with no known parent package
(参考suppliers.py中的导入)。
在这种情况下,suppliers.py 中使用的相对导入似乎失败了。请参阅下面的示例。
from importlib.machinery import SourceFileLoader
from pathlib import Path
import os
model_name = "Supplier"
parent_path = Path(__file__).resolve().parent.parent
module_path = os.path.join(parent_path, 'models', f'{model_name.lower()}s.py')
Model = getattr(SourceFileLoader(model, module_path).load_module(), model_name)
编辑:为了完整起见,抛出 ModuleNotFoundError: No module named '.'
。所以也不行。
model = __import__(f"..models.{model.lower()}.{model}")
我错过了什么?
以下是文档中有关如何在给定文件路径的情况下加载模块的方法: https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
...
import importlib
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
不使用路径库:
(我保留这个是因为文件名操作和目录处理的例子可能仍然需要,即使按照上面的方法)
的确,在给定 Python 中的 file-path 的情况下,导入文件的正确方法很复杂。无需搜索其他食谱,这里有一种方法
临时修补 sys.path,并调用普通 __import__
从指定的目录
(Python 文件的路径应使用文件系统符号给出:/
分隔符,而不是 .
。不过,此代码将忽略文件扩展名)
import sys
from pathlib import Path
def importpath(path):
strpath = str(path)
if not strpath.startswith("/"):
parent_path = Path(sys._getframe().f_globals.get("__file__", ".")).parent
path = parent_path / path
else:
path = Path(path)
try:
sys.path.insert(0, str(path.parent))
module = __import__(path.stem)
finally:
sys.path.pop(0)
return module
但是,此代码会将给定文件作为单独的 Python 模块导入,而不知道它应该在哪个包中。这意味着如果该模块中有任何相关导入,它们将失败.
阅读更多内容后,发现解决方案就在眼前。
您可以使用 getattr
def find_my_class(class_name):
from .. import models as configuration_models
module = getattr(configuration_models, f"{class_name.lower()}s")
return getattr(module, class_name)