使用 `importlib` 从 Python 模块中仅导入特定类

Posted

技术标签:

【中文标题】使用 `importlib` 从 Python 模块中仅导入特定类【英文标题】:Importing only a specific class from a Python module with `importlib` 【发布时间】:2022-01-05 21:17:49 【问题描述】:

如何使用路径从 Python 模块中导入特定类?

我需要使用文件路径从 Python 文件中导入特定类。我无法控制文件及其完全在我的包之外。

文件.py:

class Wanted(metaclass=MyMeta):
    ...

class Unwanted(metaclass=MyMeta):
    ...

元类实现在这里不相关。但是,我会指出它是我的软件包的一部分,我可以完全控制它。

导入示例:

spec = importlib.util.spec_from_file_location(name='Wanted', location="path_to_module/mudule.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

这有效,Wanted 被导入。问题是Unwanted 也被导入了。实际上,只要为name(包括空字符串)提供any字符串值,WantedUnwanted 都会从模块中导入。

这与之前的示例具有相同的效果,其中 WantedUnwanted 都被导入:

importlib.util.spec_from_file_location(name='random string', location="path_to_module/mudule.py")

我不是在寻找使用 importlib 的特定解决方案;任何合理的方式都可以。我会指出,我不需要在导入类时使用它,我只需要进行导入,然后我的元类会处理其余的事情。

【问题讨论】:

任何形式的导入都会执行整个文件。如果你不能忍受,那么这两个类不应该在同一个文件中 @john-hen 有点断章取义,但是元类注册了它们,但是如果包含该组件的模块恰好有另一个配置指定只需要 1 个“组件”派生类这两个组件都会被执行,那是个问题。但我有我的答案,应该可以在元类中解决,我只是希望有一个更简单的解决方案。 【参考方案1】:

如果我没记错的话,name 参数只是用来命名你要导入的模块。但是,更重要的是,当您导入任何模块时,您正在执行整个文件,这意味着在您的情况下,这两个类都将被创建。无论您是写from file import Wantedimport file 还是使用任何其他形式的导入语句都无关紧要。

Python 程序由代码块构成。块是作为一个单元执行的一段 Python 程序文本。以下是块:模块、函数体和类定义。

来源:https://docs.python.org/3/reference/executionmodel.html#structure-of-a-program

【讨论】:

感谢您的意见,我有点怀疑是这种情况。有没有办法以其他方式获得所需的行为? 正如@jasonharper 所说,如果创建这两个类时不合适,它们应该位于单独的模块中,或者您应该以某种方式更改元类的实现。我不知道细节,所以我真的帮不上忙。【参考方案2】:

因为您将文件命名为“file.py”:

from file import Wanted

如果您的文件在文件夹中,您可以使用:

from folder.file import Wanted

【讨论】:

感谢您的帮助。但是您的方法不起作用,正如我在“我无法控制文件及其完全在我的包之外”的问题中提到的那样。为了像您建议的那样简单地导入,该文件必须是您从中导入的包的一部分,但事实并非如此,此外,相对导入被认为是不好的做法,因为它们与运行路径相关,而不是它们所在的文件进口的。

以上是关于使用 `importlib` 从 Python 模块中仅导入特定类的主要内容,如果未能解决你的问题,请参考以下文章

在 python3 中使用 importlib 动态导入时出错

Python importlib(动态导入模块)

如何使用 importlib.import_module 在 Python 中导入模块

python3使用importlib来重复加载模块

介绍importlib

AttributeError:模块“importlib”没有属性“util”