检测循环进口 [英] Detecting circular imports
问题描述
我正在处理一个包含约30个独特模块的项目。它的设计不太好,因此在向项目添加一些新功能时通常会创建循环导入。
I'm working with a project that contains about 30 unique modules. It wasn't designed too well, so it's common that I create circular imports when adding some new functionality to the project.
当然,当我添加循环导入时,我不知道。有时很明显,当我收到类似 AttributeError之类的错误时,我已经进行了循环导入:'module'对象没有属性'attribute'
我明确定义了属性
。但是有时候,代码不会因为使用方式而引发异常。
Of course, when I add the circular import, I'm unaware of it. Sometimes it's pretty obvious I've made a circular import when I get an error like AttributeError: 'module' object has no attribute 'attribute'
where I clearly defined 'attribute'
. But other times, the code doesn't throw exceptions because of the way it's used.
所以,我的问题是:
是否可以通过编程方式检测何时以及在何处进行循环进口?
Is it possible to programmatically detect when and where a circular import is occuring?
到目前为止,我唯一能想到的解决方案是拥有一个模块 importTracking
,其中包含一个字典 importingModules
,一个函数 importInProgress(file)
,它会增加 importingModules [file]
的值,如果大于1,则抛出错误,而函数 importComplete(file)
会减小 importingModules [file]
。所有其他模块如下所示:
The only solution I can think of so far is to have a module importTracking
that contains a dict importingModules
, a function importInProgress(file)
, which increments importingModules[file]
, and throws an error if it's greater than 1, and a function importComplete(file)
which decrements importingModules[file]
. All other modules would look like:
import importTracking
importTracking.importInProgress(__file__)
#module code goes here.
importTracking.importComplete(__file__)
但这看上去真的很讨厌,必须有一个
But that looks really nasty, there's got to be a better way to do it, right?
推荐答案
为避免更改每个模块,您可以将导入跟踪功能保留在导入挂钩,或在自定义的 __ import __
您可以坚持使用内置插件-后者一次可能会更好,因为即使导入的模块被调用,也会调用 __ import __
在 sys.modules
中已经存在,在循环导入时就是这种情况。
To avoid having to alter every module, you could stick your import-tracking functionality in a import hook, or in a customized __import__
you could stick in the built-ins -- the latter, for once, might work better, because __import__
gets called even if the module getting imported is already in sys.modules
, which is the case during circular imports.
对于该实现,我只使用一组正在导入过程中的模块,类似于(benjaoming编辑:插入从原始文件派生的片段):
For the implementation I'd simply use a set of the modules "in the process of being imported", something like (benjaoming edit: Inserting a working snippet derived from original):
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
这篇关于检测循环进口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!