如何跟踪Python导入

25 投票
4 回答
8151 浏览
提问于 2025-04-15 16:28

我在给一个很大的应用程序添加新代码时遇到了循环导入的问题,现在想找出哪些文件最可能导致这个问题。有没有什么方法可以追踪哪些文件导入了哪些文件呢?我查了一下,发现了Python的trace命令,但它只显示了主Python库中的一些活动。

我其实想找一个工具,能给我展示类似这样的内容:

App1 >>imports>> App2,App3.method
App2 >>imports>> App3,etc

我可以逐个查看我的所有文件,但我不想这么做,因为这个应用程序太大了。

4 个回答

10

试着用 python -v 来运行你的程序。这样可以跟踪程序中导入模块的顺序。

另一个选择是 pylint,它会提醒你各种问题,包括循环导入的问题。

16

这里有一个简单(虽然有点粗糙;-))的方法,可以追踪“谁在尝试导入什么”,也就是模块名称:

import inspect
import __builtin__
savimp = __builtin__.__import__

def newimp(name, *x):
  caller = inspect.currentframe().f_back
  print name, caller.f_globals.get('__name__')
  return savimp(name, *x)

__builtin__.__import__ = newimp

比如说,如果你把这个保存为 tracimp.py,你会得到这样的结果:

$ python -c 'import tracimp; import email; import sys; import email.mime'
email __main__
sys email
email.mime email
sys __main__
email.mime __main__

正如你所看到的,"包装" __import__ 这个内置函数的一个特别之处在于,即使要导入的模块已经在 sys.modules 中,它也不会被静默处理:因为处理这个问题是 __import__ 的工作之一,所以我们的包装函数会在“第一次加载的模块”和“只是从 sys.modules 中获取的模块”(因为它们之前已经被导入过)这两种情况下都被调用。当你试图诊断循环导入问题时,这个特性会非常有用(这实际上就是在找出有向图中的循环,图的边由两个模块名称——被导入者和导入者——来标识,而这个简单的方法在每一行输出中都会打印出来)。

12

你可以使用以下这些脚本来制作Python模块的依赖关系图:

撰写回答