在Python中查找模块路径而不导入

60 投票
5 回答
16652 浏览
提问于 2025-04-16 09:58

我看到过几种方法可以通过先导入一个模块来找到它的路径。有没有办法在不导入模块的情况下找到这个路径呢?

5 个回答

1

对于大多数使用场景,其实你不需要依赖第三方的帮助。importlib.util.find_spec 从 Python 3.4 开始就已经存在了,它可以解决顶层导入的问题:

>>> import importlib.util
>>> spec = importlib.util.find_spec("foo")
>>> spec.origin
/home/me/my_venv/python3.11/site-packages/foo/__init__.py

还有一个便携的版本,可以获取父文件夹:

[...]
>>> from pathlib import Path
>>> Path(spec.origin).parent
/home/me/my_venv/python3.11/site-packages/foo

注意事项:

  • 对于子包(比如 foo.bar),父包会被实际导入。由于 Python 的动态特性,包括导入的解析方式,没有一种正确的解决方案可以不进行实际导入(比如,试着找到 os.path 的位置,但不导入 os,这就是一个真实的例子)。
  • 如果包不存在,spec 的值会是 None
  • 如果这个包实际上是一个命名空间,spec.origin 的值也会是 None
16

在Python 3中,imp这个模块已经不推荐使用了。你可以使用pkgutil(就像上面提到的那样),或者如果你使用的是Python 3.4及以上版本,可以使用importlib.util.find_spec来代替:

>>> import importlib
>>> spec = importlib.util.find_spec("threading")
>>> spec.origin
'/usr/lib64/python3.6/threading.py'
71

使用 pkgutil 模块:

>>> import pkgutil
>>> package = pkgutil.get_loader("pip")
>>> package.filename
'/usr/local/lib/python2.6/dist-packages/pip-0.7.1-py2.6.egg/pip'
>>> package = pkgutil.get_loader("threading")
>>> package.filename
'/usr/lib/python2.6/threading.py'
>>> package = pkgutil.get_loader("sqlalchemy.orm")
>>> package.filename
'/usr/lib/pymodules/python2.6/sqlalchemy/orm'

在 Python 3 中,可以用 pkgutil.get_loader("模块名称").get_filename() 来代替。

使用 imp 模块:

>>> import imp
>>> imp.find_module('sqlalchemy')
(None, '/usr/lib/pymodules/python2.6/sqlalchemy', ('', '', 5))
>>> imp.find_module('pip')
(None, '/usr/local/lib/python2.6/dist-packages/pip-0.7.1-py2.6.egg/pip', ('', '', 5))
>>> imp.find_module('threading')
(<open file '/usr/lib/python2.6/threading.py', mode 'U' at 0x7fb708573db0>, '/usr/lib/python2.6/threading.py', ('.py', 'U', 1))

注意:使用 imp 模块时,你不能像这样做 imp.find_module('sqlalchmy.orm')

撰写回答