检测循环进口

Pon*_*dle 17 python circular-dependency

我正在使用一个包含大约30个独特模块的项目.它设计得不太好,因此在向项目添加一些新功能时创建循环导入是很常见的.

当然,当我添加循环导入时,我不知道它.有时很明显,当我得到一个像AttributeError: 'module' object has no attribute 'attribute'我明确定义的错误时,我已经进行了循环导入'attribute'.但其他时候,代码不会因为它的使用方式而抛出异常.

所以,对我的问题:

是否有可能以编程方式检测循环导入的发生时间和位置?

到目前为止,我能想到的唯一解决方案是拥有一个importTracking包含dict importingModules,一个函数的模块,该函数importInProgress(file)会递增importingModules[file],如果大于1则抛出错误,并且函数importComplete(file)会递减importingModules[file].所有其他模块看起来像:

import importTracking
importTracking.importInProgress(__file__)
#module code goes here.
importTracking.importComplete(__file__)
Run Code Online (Sandbox Code Playgroud)

但这看起来真的很讨厌,必须有更好的方法去做,对吗?

Ale*_*lli 8

为了避免必须改变每个模块,你可以将导入跟踪功能放在导入钩子中,或者在定制中__import__你可以坚持使用内置插件 - 后者,一次,可能会更好,因为__import__即使导入的模块已经存在sys.modules,循环导入时就是这种情况.

对于实现,我只是使用"在导入过程中"的一组模块,类似于(benjaoming edit:插入一个源自原始的工作片段):

beingimported = set()
originalimport = __import__
def newimport(modulename, *args, **kwargs):
    if modulename in beingimported:
        print "Importing in circles", modulename, args, kwargs
        print "    Import stack trace -> ", beingimported
        # sys.exit(1) # Normally exiting is a bad idea.
    beingimported.add(modulename)
    result = originalimport(modulename, *args, **kwargs)
    if modulename in beingimported:
        beingimported.remove(modulename)
    return result
import __builtin__
__builtin__.__import__ = newimport
Run Code Online (Sandbox Code Playgroud)