Python 模块导入被调用模块污染
Python module imports polluted by calling module
我创建了模块 B
,它在其函数 foo()
中进行了一些昂贵的网络调用。所以我创建了一个模块 mockB
用于测试。 mockB
有一个名为 mockfoo()
的方法,它是 B.foo()
的模拟,另一个名为 patch()
的方法,它以模块 B
的实例作为参数,并且用 mockfoo()
.
覆盖它的 foo()
方法
B.py
def foo():
print 'foo()'
模拟B.py
def patch(B_module):
B_module.foo = mock_foo
def mock_foo():
print 'mock_foo()'
模块 A
导入 B
和 mockB
并使用 mockB
修补 B
,然后调用 B.foo()
。一切都按预期工作 - 'mock_foo()'
被打印出来。
当模块 A
导入模块 C
时出现奇怪,它也是 B
的客户端,并且既不是 A
也不是 C
补丁C.B
。出于某种原因,C.do_B_thing()
打印出 'mock_foo()'
.
C.py
import B
def do_B_thing():
B.foo()
A.py
import B
import mockB
import C
from B import foo
mockB.patch(B)
# Unsurprising
print 'Calling patched B.foo():'
B.foo()
# Surprising
print 'Module C calling unpatched B.foo():'
C.do_B_thing()
# For comparison
print 'Module C calling local foo():'
foo()
输出:
$ python A.py
Calling patched B.foo():
mock_foo()
Module C calling unpatched B.foo():
mock_foo()
Module C calling local foo():
foo()
出现在 Python 2.7 和 3 中(打印语句根据需要更改为函数调用)。
这完全是预期的行为。
模块是单例。内存中只有一份(存放在sys.modules
)。导入加载模块一次,然后在导入的任何地方重复使用它。
因此,只有 一个 B.foo
对象,您将其替换为另一个函数。其他地方仍然使用 B.foo
来查找对函数的引用,所以他们看到被替换的对象。
如果您需要临时模拟某些东西,您需要确保在完成后 re-instate 原始对象。 Python 3) 中的 mock
library (unittest.mock
可以为您做到这一点。
或者,创建对函数对象的本地引用。如果您使用:
from B import foo
foo()
您创建了对 foo
本身的新引用。稍后替换 B.foo
不会改变此 'local' foo
参考。
我创建了模块 B
,它在其函数 foo()
中进行了一些昂贵的网络调用。所以我创建了一个模块 mockB
用于测试。 mockB
有一个名为 mockfoo()
的方法,它是 B.foo()
的模拟,另一个名为 patch()
的方法,它以模块 B
的实例作为参数,并且用 mockfoo()
.
foo()
方法
B.py
def foo():
print 'foo()'
模拟B.py
def patch(B_module):
B_module.foo = mock_foo
def mock_foo():
print 'mock_foo()'
模块 A
导入 B
和 mockB
并使用 mockB
修补 B
,然后调用 B.foo()
。一切都按预期工作 - 'mock_foo()'
被打印出来。
当模块 A
导入模块 C
时出现奇怪,它也是 B
的客户端,并且既不是 A
也不是 C
补丁C.B
。出于某种原因,C.do_B_thing()
打印出 'mock_foo()'
.
C.py
import B
def do_B_thing():
B.foo()
A.py
import B
import mockB
import C
from B import foo
mockB.patch(B)
# Unsurprising
print 'Calling patched B.foo():'
B.foo()
# Surprising
print 'Module C calling unpatched B.foo():'
C.do_B_thing()
# For comparison
print 'Module C calling local foo():'
foo()
输出:
$ python A.py
Calling patched B.foo():
mock_foo()
Module C calling unpatched B.foo():
mock_foo()
Module C calling local foo():
foo()
出现在 Python 2.7 和 3 中(打印语句根据需要更改为函数调用)。
这完全是预期的行为。
模块是单例。内存中只有一份(存放在sys.modules
)。导入加载模块一次,然后在导入的任何地方重复使用它。
因此,只有 一个 B.foo
对象,您将其替换为另一个函数。其他地方仍然使用 B.foo
来查找对函数的引用,所以他们看到被替换的对象。
如果您需要临时模拟某些东西,您需要确保在完成后 re-instate 原始对象。 Python 3) 中的 mock
library (unittest.mock
可以为您做到这一点。
或者,创建对函数对象的本地引用。如果您使用:
from B import foo
foo()
您创建了对 foo
本身的新引用。稍后替换 B.foo
不会改变此 'local' foo
参考。