如何检查模块是否已被导入?

152

我该如何检查代码中是否导入了某个模块?

 if not has_imported("somemodule"):
     print('you have not imported somemodule')

我希望检查是否已经导入一个模块的原因是因为我有一个模块,我不想导入它,因为有时它会让我的程序出现问题。


1
只需在您不想导入的模块顶部放置 raise SystemError()(或其他您选择的异常)。如果您确实在某个地方导入了它,您的程序将抛出回溯并退出。 - larsks
导入一个模块怎么可能会毁掉你的程序呢?听起来不太可能。 - Bill Woodger
1
@BillWoodger:也许那个模块会改变你不想改变的全局状态。 - Martijn Pieters
@MartijnPieters 哎呀。并且导入声音如此中性。 - Bill Woodger
5个回答

202

测试在sys.modules字典中的模块名称:

import sys

modulename = 'datetime'
if modulename not in sys.modules:
    print 'You have not imported the {} module'.format(modulename)
根据文件:

这是一个将模块名称映射到已加载模块的字典。

请注意,import语句执行两件事:

  1. 如果模块之前从未被导入过(== 不在sys.modules中),则会加载该模块并将其添加到sys.modules中。
  2. 将一个或多个名称绑定到当前命名空间,这些名称引用模块对象或属于模块命名空间的对象。

表达式modulename not in sys.modules测试第1步是否已完成。需要了解使用了哪个确切的import语句来测试步骤2的结果,因为它们将不同的名称设置为引用不同的对象:

  • import modulename设置modulename = sys.modules['modulename']
  • import packagename.nestedmodule设置packagename = sys.modules['packagename'](无论您添加了多少级别)
  • import modulename as altname设置altname = sys.module['modulename']
  • import packagename.nestedmodule as altname设置altname = sys.modules['packagename.nestedmodule']
  • from somemodule import objectname设置objectname = sys.modules['somemodule'].objectname
  • from packagename import nestedmodulename设置nestedmodulename = sys.modules['packagename.nestedmodulename'](仅当在此导入之前packagename命名空间中没有名为nestedmodulename的对象时,才会添加一个嵌套模块的附加名称到父包命名空间中)
  • from somemodule import objectname as altname设置altname = sys.modules['somemodule'].objectname
  • from packagename import nestedmodulename as altname设置altname = sys.modules['packagename.nestedmodulename'](仅当在此导入之前packagename命名空间中没有名为nestedmodulename的对象时,才会添加一个嵌套模块的附加名称到父包命名空间中)

您可以测试导入对象绑定的名称是否存在于给定的命名空间中:

# is this name visible in the current scope:
'importedname' in dir()

# or, is this a name in the globals of the current module:
'importedname' in globals()

# or, does the name exist in the namespace of another module:
'importedname' in globals(sys.modules['somemodule'])

这只告诉你名字是否存在(已绑定),而不是它是否指向该模块的特定对象。如果需要排除自那时以来名称已被设置为完全不同的其他内容,您可以进一步检查该对象或测试其是否与sys.modules中可用的对象相同。


1
这是检查函数内是否需要的包的最佳方式吗?也就是说,假设某个函数需要 numpy 包 - 在函数内使用 import sys 来检查是否已导入它是最佳方式吗?我所指的 "最佳方式" 是指性能影响方面,因为每次调用函数时都会调用 import sys。谢谢。 - Confounded
1
@Confounded 如果你担心这个,可以在函数外部简单地导入 sys。注意,import sys 并不会造成任何性能问题;sys 总是存在的,默认已经加载了。但对于可选包,只需导入该包即可。如果未安装该包,则捕获 ImportError 异常,并设置一个标志表示其已安装,当导入成功后。此后,您可以使用该标志来通知您使用可选依赖项。 - Martijn Pieters
如何检查是否已导入sys? - Fisher
@Fisher:你不需要这样做。sys 模块始终处于活动状态。如果你需要知道 sys 是否已导入到当前全局命名空间中,你可以检查名称 sys 是否存在,但我认为这没有任何意义。 - Martijn Pieters

45

在回答sys.modules问题时,我要增加一个注意事项,即在导入时小心重命名模块:

>>> import sys
>>> import datetime as dt
>>> 'dt' in sys.modules
False
>>> 'datetime' in sys.modules
True

1
需要解释一下。 - Peter Mortensen

22

使用 sys.modules 来测试一个模块是否已经被导入(这里使用 unicodedata 作为示例):

>>> import sys
>>> 'unicodedata' in sys.modules
False
>>> import unicodedata
>>> 'unicodedata' in sys.modules
True

10

sys.modules包含了解释器中任何地方使用的所有模块,因此如果在Python中的任何其他模块中导入,它将显示出来。

dir()检查名称是否在当前命名空间中定义。

两者的组合比单独使用更安全,并且只要您没有自己定义copy,就可以正常工作。

if ('copy' in sys.modules) and ('copy' in dir()):

7

使用:

if "sys" not in dir():
  print("sys not imported!")

这在代码开头(顶部)很有效,但应该小心使用,以防另一个名为sys的对象被创建。


仅检查当前命名空间中是否导入了该模块。此外,sys 可以是任何东西,而不仅仅是一个模块。 - vaultah
1
这个答案有问题 - 如果你导入模块时使用了as关键字,那么你选择的名称将会出现在其中;例如 - import numpy as np - dir() 将包含 np 而不是 numpy - noamgot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接