暂时删除python模块

时间:2013-05-10 20:06:33

标签: python python-2.7

我正在尝试暂时从sys.modules中删除一个python模块,以便我可以将其作为测试用例的一部分导入(各种系统函数被模拟掉),然后再将其重新放回。 (是的,这有点疯狂,我可能会最终重组代码现在我很好奇......)

我可以移除模块并重新导入它就好了但是一旦我完成,我似乎无法将其重新放回原始模块。 (也许这只是不可行的?)这是我写的一个测试用例来测试这个想法:

class Test(unittest.TestCase):

    def test_assumptions(self):
        import meta.common.fileutils as fu1
        del(sys.modules["meta.common.fileutils"])
        import meta.common.fileutils
        del(sys.modules["meta.common.fileutils"])
        sys.modules["meta.common.fileutils"] = fu1 # I hoped this would set the module back
        import meta.common.fileutils as fu2
        self.assertEqual(fu1, fu2)  # assert fails, fu2 is a new copy of module :-(

有谁能说明为什么会失败?

编辑,使用其中一个答案建议的pop()也失败:

class Test(unittest.TestCase):

    def test_assumptions(self):
        import meta.common.fileutils as fu1
        orig = sys.modules.pop("meta.common.fileutils")
        import meta.common.fileutils
        del(sys.modules["meta.common.fileutils"])
        sys.modules["meta.common.fileutils"] = orig 
        import meta.common.fileutils as fu2
        self.assertEqual(fu1, orig) # passes
        self.assertEqual(fu2, orig) # fails
        self.assertEqual(fu1, fu2)  # fails

2 个答案:

答案 0 :(得分:3)

sys.modules结构实际上只是 Python dict。您可以从中删除模块,也可以将它们放回

将原始模块对象存储在局部变量中,使用dict.pop()删除模块并将其返回:

orig = sys.modules.pop('meta.common.fileutils')

然后,在恢复它时,只需将该对象放回sys.modules

sys.modules['meta.common.fileutils'] = orig

答案 1 :(得分:3)

在我看来,这里的问题与包有关。特别是,对于存在于包中的模块(例如meta.common),有两种方法可以访问它:via sys.modules,并通过父包的字典(即meta.common.__dict__) 。我认为import meta.common.fileutils as fu2行的fu2值来自meta.common.__dict__,而不是来自sys.modules

所以解决方案:除了猴子修补sys.modules之外,你还应该修补父包。即,添加如下内容:

>>> import meta.common
>>> meta.common.fileutils = fu1

sys.modules["meta.common.fileutils"] = fu1行之前。