如何获取一个Python模块导入的模块列表

6

如果有的话,我希望在Python中访问某种重要的依赖项跟踪。

我决定在我的模块中添加一个__dependencies__字典,描述了该模块导入的所有模块的版本。

我想要一种自动获取由我的模块导入的模块列表的方法。最好是在模块的最后一行。

ModuleFinder(如How to list imports within a Python module? 所建议的)不起作用,因为检查应该对已加载的模块执行。

ModuleFinder的另一个问题是它检查Python脚本(带有if __name__ == '__main__'分支),而不是一个模块。

如果我们考虑一个玩具脚本script.py:

if __name__ == '__main__':
    import foo

那么结果就是:
>>> mf = ModuleFinder
>>> mf.run_script('script.py')
>>> 'foo' in mf.modules
True

如果将脚本作为模块导入,则应该为False。

我不想列出所有导入的模块 - 只有我的模块导入的模块 - 因此sys.modules(由What is the best way of listing all imported modules in python?建议)会返回太多内容。

我可以比较模块代码开头和结尾的sys.modules的快照。但是这样,我会错过在任何其他模块之前导入的模块,但是我的模块使用了这些模块。

重要的是还要列出模块从中导入对象的模块。

如果我们考虑一个玩具模块example.py:

from foo import bar
import baz

那么结果应该是这样的:
>>> import example
>>> moduleImports(example)
{'foo': <module 'foo' from ... >,
 'baz': <module 'baz' from ...>}

它可能还包含递归导入的模块或给定bar为一个模块的foo.bar

根据如何列出导入的模块?,使用globls()需要手动处理非模块导入,例如:

from foo import bar
import bar

我该如何避免这种情况?

到目前为止,我的解决方案还存在另一个问题。在重构时,PyCharm往往会清理我的手动导入,这使得难以保持其正常工作。


不清楚您为什么认为ModuleFinder不起作用。实际上,它肯定是唯一可能起作用的东西。否则,您将如何区分已经加载的模块和首次由您的模块导入的模块?您又如何识别不在模块全局范围内的导入(例如,在函数内部)? - ekhumoro
你声称ModuleFinder不能与模块一起使用的说法显然是错误的 - 请参阅Python文档中的示例。我没有看到任何其他不使用它的好理由。 - ekhumoro
你能给一个更好的例子吗? - TheChetan
@ekhumoro 请指出导入模块的示例,然后将导入的模块(而不是 str)传递给 ModuleFinder。我看不到它。 另外,请查看更新的问题 - 我在“__main__”分支中添加了一个 ModuleFinder 失败的示例。 - abukaj
@abukaj。不,没有这样的导入跟踪。如果有的话,那么ModuleFinder的目的是什么?将检查代码放入模块中似乎不可行 - 肯定这样的代码必须执行自己的导入?我认为ModuleFinder之所以按照其方式工作,一定有非常好的理由。 - ekhumoro
显示剩余5条评论
1个回答

7
您可以使用inspect模块。
例如:
import inspect
import os
m = inspect.getmembers(os) # get module content
filter(lambda x: inspect.ismodule(x[1]), m) # filter dependant modules

这里有一个实时示例

如果您想要导入本地模块,只需使用以下命令:

filter(lambda x: inspect.ismodule(x[1]), locals().items()) # filter dependant modules

另一个 实时示例


1
谢谢。不幸的是,它具有与我的当前解决方案(过滤globals())相同的缺点。它会省略非模块导入(例如from foo import bar中的foo被忽略)。 - abukaj
@abukaj,我认为你只有手动指定才能得到这个,因为实际上 foo 不在使用中,因为 Python 没有将其带入作用域:/ - Netwave
我希望Python模块中有某种导入跟踪功能。 - abukaj
现场示例已经损坏。 - user3064538
1
你可以将谓词传递给 getmembers,例如 inspect.getmembers(os, inspect.ismodule) - user3064538

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