Python 使用 importlib 从包目录导入模块

Python use importlib to import a module from a package directory

我正在尝试使用 importlib 动态导入 PySide2,因为使用 import 静态导入 PySide2 对我的应用程序来说是不够的。我需要 importlib 因为最后它将与 pyinstaller 一起使用来创建一个可以动态导入 PySide2 的可执行文件,而不仅仅是从单个可执行文件。

我已经复制了用 pip 下载的整个 PySide2 包目录。这个 PySide2 版本比我默认使用的版本旧,当 "PySide2" 目录出现在我的源目录中时,我想改用它。

根据this post中的答案,我有以下代码来执行导入:

import os, sys
print("Import test")
if os.path.isdir('./PySide2/'):
    print('Importing local PySide2')
    import importlib.util

    MODULE_PATH = "./PySide2/__init__.py"
    MODULE_NAME = "PySide2"

    spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
    print("spec.name is " + str(spec.name))
    module = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = module 
    print(sys.modules)
    spec.loader.exec_module(module)

    print(PySide2.__version__)
else:
    print('Importing system PySide2')
    import PySide2
    print(PySide2.__version__)

但是当我 运行 它时,我得到 NameError: name 'PySide2' is not defined,即使我在 sys.modules 中看到 PySide2 存在(在下面的输出中一直向右滚动到看到它存在):

$ python importTest.py
Import test
Importing local PySide2
spec.name is PySide2
{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap' (frozen)>, '_imp': <module '_imp' (built-in)>, '_thread': <module '_thread' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_weakref': <module '_weakref' (built-in)>, 'zipimport': <module 'zipimport' (built-in)>, '_frozen_importlib_external': <module 'importlib._bootstrap_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>, 'encodings': <module 'encodings' from '/usr/lib/python3.7/encodings/__init__.py'>, 'codecs': <module 'codecs' from '/usr/lib/python3.7/codecs.py'>, '_codecs': <module '_codecs' (built-in)>, 'encodings.aliases': <module 'encodings.aliases' from '/usr/lib/python3.7/encodings/aliases.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from '/usr/lib/python3.7/encodings/utf_8.py'>, '_signal': <module '_signal' (built-in)>, '__main__': <module '__main__' from 'importTest.py'>, 'encodings.latin_1': <module 'encodings.latin_1' from '/usr/lib/python3.7/encodings/latin_1.py'>, 'io': <module 'io' from '/usr/lib/python3.7/io.py'>, 'abc': <module 'abc' from '/usr/lib/python3.7/abc.py'>, '_abc': <module '_abc' (built-in)>, 'site': <module 'site' from '/usr/lib/python3.7/site.py'>, 'os': <module 'os' from '/usr/lib/python3.7/os.py'>, 'stat': <module 'stat' from '/usr/lib/python3.7/stat.py'>, '_stat': <module '_stat' (built-in)>, 'posixpath': <module 'posixpath' from '/usr/lib/python3.7/posixpath.py'>, 'genericpath': <module 'genericpath' from '/usr/lib/python3.7/genericpath.py'>, 'os.path': <module 'posixpath' from '/usr/lib/python3.7/posixpath.py'>, '_collections_abc': <module '_collections_abc' from '/usr/lib/python3.7/_collections_abc.py'>, '_sitebuiltins': <module '_sitebuiltins' from '/usr/lib/python3.7/_sitebuiltins.py'>, 'sitecustomize': <module 'sitecustomize' from '/usr/lib/python3.7/sitecustomize.py'>, 'importlib': <module 'importlib' from '/usr/lib/python3.7/importlib/__init__.py'>, 'importlib._bootstrap': <module 'importlib._bootstrap' (frozen)>, 'importlib._bootstrap_external': <module 'importlib._bootstrap_external' (frozen)>, 'types': <module 'types' from '/usr/lib/python3.7/types.py'>, 'warnings': <module 'warnings' from '/usr/lib/python3.7/warnings.py'>, 'importlib.util': <module 'importlib.util' from '/usr/lib/python3.7/importlib/util.py'>, 'importlib.abc': <module 'importlib.abc' from '/usr/lib/python3.7/importlib/abc.py'>, 'importlib.machinery': <module 'importlib.machinery' from '/usr/lib/python3.7/importlib/machinery.py'>, 'contextlib': <module 'contextlib' from '/usr/lib/python3.7/contextlib.py'>, 'collections': <module 'collections' from '/usr/lib/python3.7/collections/__init__.py'>, 'operator': <module 'operator' from '/usr/lib/python3.7/operator.py'>, '_operator': <module '_operator' (built-in)>, 'keyword': <module 'keyword' from '/usr/lib/python3.7/keyword.py'>, 'heapq': <module 'heapq' from '/usr/lib/python3.7/heapq.py'>, '_heapq': <module '_heapq' (built-in)>, 'itertools': <module 'itertools' (built-in)>, 'reprlib': <module 'reprlib' from '/usr/lib/python3.7/reprlib.py'>, '_collections': <module '_collections' (built-in)>, 'functools': <module 'functools' from '/usr/lib/python3.7/functools.py'>, '_functools': <module '_functools' (built-in)>, 'PySide2': <module 'PySide2' from './PySide2/__init__.py'>}
Traceback (most recent call last):
  File "importTest.py", line 17, in <module>
    print(PySide2.__version__)
NameError: name 'PySide2' is not defined

我不明白为什么在 sys.modules.

中显示 "name 'PySide2' is not define"

documentation 开始,当找不到本地或全局名称时会引发 NameError

对于标准导入语句, 它会做以下事情:

  • 查找并加载模块
  • 更新sys.modules
  • 使用指向 import foo 的实际模块对象的变量名称更新全局字典,当 import * from something 时更新多个变量(同时检查模块的 __all__

这里你已经手动完成了前2个步骤,你只需要添加:

PySide2 = module