如何跟踪Python导入
我在给一个很大的应用程序添加新代码时遇到了循环导入的问题,现在想找出哪些文件最可能导致这个问题。有没有什么方法可以追踪哪些文件导入了哪些文件呢?我查了一下,发现了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模块的依赖关系图: