【问题标题】:Using importlib.import_module over an import statement在 import 语句上使用 importlib.import_module
【发布时间】:2020-07-29 13:55:39
【问题描述】:

我使用的 api -- smartsheet-python-sdk 从源代码执行时运行良好。但是,当我使用 PyInstaller 进行打包时,我收到了一个错误,因为 PyInstaller 找不到必要的模块。在 smartsheet 库中,它使用 importlib.import_module 从库中导入模块。

    def __getattr__(self, name):
        """
        Handle sub-class instantiation.

        Args:
            name (str): Name of smartsheet to instantiate.

        Returns:
            Instance of named class.
        """
        try:
            # api class first
            class_ = getattr(importlib.import_module(
                __package__ + '.' + name.lower()), name)
            return class_(self)
        except ImportError:
            # model class next:
            try:
                class_ = getattr(importlib.import_module(
                    name.lower()), name)
                return class_()
            except ImportError:
                self._log.error(
                    'ImportError! Could not load api or model class %s', name)
                return name

当它只从自己的库中导入模块而不是仅仅将导入语句添加到已知模块时,使用这样的东西有什么客观好处吗?

【问题讨论】:

  • 如果您在变量中有模块名称,例如module_name = 'sys',您不能使用 import 语句导入它,但您可以这样做 importlib.import_module(module_name)
  • 但是它只是导入自己的模块,为什么它需要是一个字符串而不是仅仅导入静态模块。 smartsheet.sheets 将使用 pyinstaller 抛出错误,因为 sheets 永远不会被拾取。
  • @Software2 不是真的,我知道它允许动态导入,我只是不明白这种特殊情况需要这样做的原因,因为它只会引用它自己的模块。除非我完全遗漏了某些东西(当然不是不可能的),否则似乎只导入它们就不太容易出错。所以基本上除了能够动态导入之外还有一个优势。

标签: python import smartsheet-api


【解决方案1】:

从实际的角度来看,这种方法之所以有利有几个不同的原因。

方便

明确列出模块需要执行额外的步骤来集成新模块。声明导入的这一步可以完全省略。

不易出错

如果不经常添加新模块,忘记在正确位置导入模块是可能发生的简单小错误之一。删除该要求意味着不会发生错误。这种方法会有其他缺点吗?当然可以,但这些权衡的重要性是主观的。

可扩展性

在你写的评论中

我只是不明白这种特殊情况需要这样做的原因,因为 它只会引用它自己的模块。

这是一个错误的假设。一个模块完全有可能在未来某个时间点来自另一个位置。不太可能?也许吧,但这种设计允许更轻松地添加新的可能位置 - 这里使用了两个位置,第三个当然是可能的。例如,也许模拟用于测试目的。当然还有其他可行的方法,但这似乎是这种方法的一个可能原因。

但是 PyInstaller 呢?

最终,您是正确的,这种方法很难轻松加载到 PyInstaller 中。从their documentation 开始,您可以将一些变通方法应用于构建过程的脚本。 (为方便起见,复制到这里)

某些 Python 脚本以 PyInstaller 无法检测到的方式导入模块:例如,通过使用带有可变数据的 __import__() 函数、使用 imp.find_module() 或在运行时操纵 sys.path 值。如果你的脚本需要 PyInstaller 不知道的文件,你必须帮助它:

  • 您可以在pyinstaller 命令行上提供其他文件。
  • 您可以在命令行中提供其他导入路径。
  • 您可以编辑 PyInstaller 第一次为您的脚本运行它时编写的 myscript.spec 文件。在规范文件中,您可以告诉 PyInstaller 您的脚本独有的代码模块。
  • 您可以编写通知 PyInstaller 隐藏导入的“挂钩”文件。如果您为其他用户也可能使用的包创建“挂钩”,则可以将挂钩文件贡献给 PyInstaller。

【讨论】:

  • 如果动态加载的模块位于例如 C:/dev/myModules 上,它将如何在 pyinstaller 命令行或 .spec 文件中转换,然后获取带有 .exe 的文件夹?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 2020-09-12
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 2015-12-18
相关资源
最近更新 更多