我如何知道Python模块是否存在,而不导入它?
导入一些可能不存在(不是我想要的)的东西会导致:
try:
import eggs
except ImportError:
pass
我如何知道Python模块是否存在,而不导入它?
导入一些可能不存在(不是我想要的)的东西会导致:
try:
import eggs
except ImportError:
pass
当前回答
Python 2,不依赖于ImportError
在当前答案更新之前,以下是Python 2的方法
import pkgutil
import importlib
if pkgutil.find_loader(mod) is not None:
return importlib.import_module(mod)
return None
为什么又是另一个答案?
很多答案都利用了捕捉ImportError。问题是,我们不知道是什么引发了ImportError。
如果你导入了你现有的模块,而你的模块中恰好有一个ImportError(例如,第1行有错字),结果将是你的模块不存在。
这将花费您大量的回溯来确定您的模块是否存在,ImportError被捕获并使事情无声地失败。
其他回答
Python 3 >= 3.6: ModuleNotFoundError
ModuleNotFoundError已在Python 3.6中引入,可用于以下目的:
try:
import eggs
except ModuleNotFoundError:
# Error handling
pass
当无法找到模块或其父模块之一时,将引发此错误。所以
try:
import eggs.sub
except ModuleNotFoundError as err:
# Error handling
print(err)
如果找不到eggs模块,将打印类似于No module named 'eggs'的消息;但它会打印类似于没有名为“eggs”的模块。如果子模块找不到,但鸡蛋包可以找到,则Sub '。
有关ModuleNotFoundError的更多信息,请参阅导入系统的文档。
使用importlib.util.find_spec(module_name) (Python 3.4+)。
Python2: imp.find_module
要检查import是否能在python2中找到一些东西,使用imp:
import imp
try:
imp.find_module('eggs')
found = True
except ImportError:
found = False
要找到点导入,你需要做更多的事情:
import imp
try:
spam_info = imp.find_module('spam')
spam = imp.load_module('spam', *spam_info)
imp.find_module('eggs', spam.__path__) # __path__ is already a list
found = True
except ImportError:
found = False
也可以使用pkgutil。find_loader(与Python 3部分大致相同:
import pkgutil
eggs_loader = pkgutil.find_loader('eggs')
found = eggs_loader is not None
Python 3
Python 3≤3.3:importlib.find_loader
你应该使用importlib。我是这样做的:
import importlib
spam_loader = importlib.find_loader('spam')
found = spam_loader is not None
我的期望是,如果你能找到一个加载器,那么它就存在了。你也可以更聪明一点,比如过滤掉你将接受的加载器。例如:
import importlib
spam_loader = importlib.find_loader('spam')
# only accept it as valid if there is a source file for the module - no bytecode only.
found = issubclass(type(spam_loader), importlib.machinery.SourceFileLoader)
Python 3≥3.4:importlib.util.find_spec
在Python 3.4中importlib。Python文档已弃用,取而代之的是importlib.util.find_spec。推荐使用importlib.util.find_spec方法。还有其他的,比如进口机械。FileFinder,如果你想要加载一个特定的文件,它很有用。弄清楚如何使用它们超出了本文的范围。
import importlib
spam_spec = importlib.util.find_spec("spam")
found = spam_spec is not None
这也适用于相对导入,但你必须提供初始包,所以你还可以这样做:
import importlib
spam_spec = importlib.util.find_spec("..spam", package="eggs.bar")
found = spam_spec is not None
spam_spec.name == "eggs.spam"
虽然我确信这样做是有原因的,但我不确定是什么原因。
警告
当试图找到子模块时,它将导入父模块(对于上述所有方法)!
food/
|- __init__.py
|- eggs.py
## __init__.py
print("module food loaded")
## eggs.py
print("module eggs")
were you then to run
>>> import importlib
>>> spam_spec = importlib.util.find_spec("food.eggs")
module food loaded
ModuleSpec(name='food.eggs', loader=<_frozen_importlib.SourceFileLoader object at 0x10221df28>, origin='/home/user/food/eggs.py')
欢迎就如何解决这个问题发表评论
确认
@rvighne for importlib @lucas-guido for Python 3.3+弃用find_loader @enpenax for pkgutils。Python 2.7中的find_loader行为
没有任何方法可以在不导入其父包的情况下可靠地检查“虚线模块”是否可导入。说到这里,对于“如何检查Python模块是否存在”这个问题,有很多解决方案。
下面的解决方案解决了导入的模块即使存在也会引发ImportError的问题。我们希望将这种情况与模块不存在的情况区分开来。
Python 2:
import importlib
import pkgutil
import sys
def find_module(full_module_name):
"""
Returns module object if module `full_module_name` can be imported.
Returns None if module does not exist.
Exception is raised if (existing) module raises exception during its import.
"""
module = sys.modules.get(full_module_name)
if module is None:
module_path_tail = full_module_name.split('.')
module_path_head = []
loader = True
while module_path_tail and loader:
module_path_head.append(module_path_tail.pop(0))
module_name = ".".join(module_path_head)
loader = bool(pkgutil.find_loader(module_name))
if not loader:
# Double check if module realy does not exist
# (case: full_module_name == 'paste.deploy')
try:
importlib.import_module(module_name)
except ImportError:
pass
else:
loader = True
if loader:
module = importlib.import_module(full_module_name)
return module
Python 3:
import importlib
def find_module(full_module_name):
"""
Returns module object if module `full_module_name` can be imported.
Returns None if module does not exist.
Exception is raised if (existing) module raises exception during its import.
"""
try:
return importlib.import_module(full_module_name)
except ImportError as exc:
if not (full_module_name + '.').startswith(exc.name + '.'):
raise
使用pkgutil中的一个函数,例如:
from pkgutil import iter_modules
def module_exists(module_name):
return module_name in (name for loader, name, ispkg in iter_modules())
在使用yarbelk的响应后,我做了这个,所以我不需要导入ìmp。
try:
__import__('imp').find_module('eggs')
# Make things with a supposed existing module
except ImportError:
pass
例如,它在Django的settings.py文件中就很有用。