什么原因会导致一个 Python 模块被导入两次?
什么原因会导致一个 Python 模块被导入两次?
据我所知,Python模块不会被重复导入,即模块中的代码只在第一次导入时执行。后续的导入语句只是将该模块添加到导入的范围中。
然而,我有一个名为"TiledConvC3D.py"的模块似乎被多次导入。我使用pdb在该模块的代码顶部打印堆栈。
以下是模块第一次执行时堆栈跟踪的末尾:
File "/python_modules/Theano/theano/gof/cmodule.py",第328行,在refresh函数中 key = cPickle.load(open(key_pkl, 'rb')) File " /ops/TiledConvG3D.py",第565行,在 中 import TiledConvC3D File " /ops/TiledConvC3D.py",第18行,在 中 pdb.traceback.print_stack()
它继续执行几次。然而,第二次调用它时的完整堆栈跟踪没有显示任何调用reload
,所以这些执行不应该发生:
File "sup_train_conj_grad.py",第103行,在中 dataset = Config.get_dataset(dataset_node) File " /Config.py",第279行,在get_dataset函数中 from datasets import NewWiskott File " /datasets/NewWiskott.py",第16行,在 中 normalizer_train = video.ContrastNormalizer3D(sigma, global_per_frame = False, input_is_5d = True) File " /util/video.py",第204行,在__init__函数中 self.f = theano.function([input],output) File " /python_modules/Theano/theano/compile/function.py",第105行,在function函数中 allow_input_downcast=allow_input_downcast) File " /python_modules/Theano/theano/compile/pfunc.py",第270行,在pfunc函数中 accept_inplace=accept_inplace, name=name) File " /python_modules/Theano/theano/compile/function_module.py",第1105行,在orig_function函数中 fn = Maker(inputs, outputs, mode, accept_inplace = accept_inplace).create(defaults) File "/u/goodfeli/python_modules/Theano/theano/compile/function_module.py",第982行,在create函数中 _fn, _i, _o = self.linker.make_thunk(input_storage = input_storage_lists) File " /python_modules/Theano/theano/gof/link.py",第321行,在make_thunk函数中 output_storage = output_storage)[:3] File " /python_modules/Theano/theano/gof/cc.py",第1178行,在make_all函数中 output_storage = node_output_storage) File " /python_modules/Theano/theano/gof/cc.py",第774行,在make_thunk函数中 cthunk, in_storage, out_storage, error_storage = self.__compile__(input_storage, output_storage) File " /python_modules/Theano/theano/gof/cc.py",第723行,在__compile__函数中 output_storage) File " /python_modules/Theano/theano/gof/cc.py",第1037行,在cthunk_factory函数中 module = get_module_cache().module_from_key(key=key, fn=self.compile_cmodule) File " /python_modules/Theano/theano/gof/cc.py",第59行,在get_module_cache函数中 return cmodule.get_module_cache(config.compiledir) File " /python_modules/Theano/theano/gof/cmodule.py",第576行,在get_module_cache函数中 _module_cache = ModuleCache(dirname, force_fresh=force_fresh) File " /python_modules/Theano/theano/gof/cmodule.py",第268行,在__init__函数中 self.refresh() File " /python_modules/Theano/theano/gof/cmodule.py",第326行,在refresh函数中 key = cPickle.load(open(key_pkl, 'rb')) File " /ops/TiledConvV3D.py",第504行,在 中 import TiledConvG3D File " /ops/TiledConvG3D.py",第565行,在 中 import TiledConvC3D File " /ops/TiledConvC3D.py",第22行,在 中 pdb.traceback.print_stack()
此外,我还检查了__builtin__.__import__
的id。在我的主脚本的开头,我导入__builtin__
并打印id(__builtin__.__import__)
,然后再进行其他导入。我还从我的被多次导入的模块中打印id(__builtin__.import__)
,而id的值没有发生变化。
除了调用reload和重写__builtin__.__import__
,还有其他机制可以解释我的模块为什么会被多次加载吗?
在我的情况下,当我在调试模式下运行Flask时,它可能会加载模块不止两次,而是多次。这种情况发生在我身上,我就是无法理解,直到我找到了这个问题。以下是更多信息:
在上述链接中,有人遇到了类似的问题,他们发现问题是由于Flask的调试模式导致的。在调试模式下,Flask会自动监测代码的更改并重新加载模块。这意味着每次更改代码后,Flask都会重新加载模块,从而导致模块被导入多次的问题。
解决这个问题的方法是禁用Flask的调试模式。可以通过在运行Flask应用程序时将调试模式设置为False来实现。这样一来,Flask将不会自动重新加载模块,解决了模块被导入多次的问题。
以下是禁用Flask调试模式的示例代码:
app = Flask(__name__) app.debug = False
在上面的代码中,我们将Flask应用程序的调试模式设置为False,从而禁用了调试模式。这样一来,即使我们在运行应用程序时进行了代码更改,Flask也不会重新加载模块,避免了模块被导入多次的问题。
希望这些信息能够帮助到其他人解决类似的问题。如果你还有其他问题,可以在上面提供的链接中找到更多有关Flask调试模式的讨论。
出现这种情况的原因是当Python模块在路径中被找到了两次时,它会被导入两次。如果项目的布局如上所示,那么就会出现这种情况。假设PYTHONPATH(sys.path)包括src和src/package1。在这种情况下,可以像下面这样导入相同的模块两次,Python会认为它们是不同的模块:
from package1 import spam
import spam
还有一种情况是,如果在第一次导入过程中出现异常,模块也可能被导入两次。例如,如果spam导入eggs,但是导入eggs时发生了异常,那么模块可以再次被导入。
这个问题的解决方法是,在导入模块时避免重复导入。可以使用try语句来包裹导入语句,以捕获导入过程中的异常,并处理异常情况。
出现这个问题后,如果有人决定再次导入模块,模块级变量将会再次被初始化,这样使用起来就非常不安全了。这对于装饰器来说尤其重要,因为它们在导入过程中的多个点上运行。
关于每种导入spam的方式在sys.modules中的键是什么,可以参考一些文档(比如python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html#the-double-import-trap)。