为何Python Mock仅在特定模块导入方式下生效?
为什么两种导入方式下Mock
utils.get_id的效果不同? 这本质是Python导入语句的命名空间绑定逻辑差异,和传值/传引用无关,下面拆解两种情况的运行机制:
1. 第一种导入:from utils import get_id
当car.py用这种写法时,Python会执行以下操作:
- 加载
utils模块(未加载过的话) - 在
car模块的独立命名空间里,创建一个名为get_id的变量,直接指向原utils.get_id函数对象 - 后续
Car.setup里调用的get_id(),实际是调用car模块命名空间里的这个变量指向的对象
你在测试代码里修改的是utils.get_id——也就是把utils模块命名空间里的get_id变量换成了Mock对象,但car模块里的get_id变量仍然指向原来的函数。这就像:
a = [1,2,3] b = a a = [4,5,6] # b还是[1,2,3],因为a和b是两个独立变量,只是最初指向同一对象
car.get_id和utils.get_id就是例子里的b和a,修改其中一个的指向不会影响另一个。
2. 第二种导入:from . import utils
改成这种写法后,Python的逻辑变成:
- 加载
utils模块(未加载过的话) - 在
car模块的命名空间里创建一个名为utils的变量,指向整个utils模块对象 - 后续
Car.setup里调用的utils.get_id(),是先通过car.utils找到模块对象,再从模块对象的命名空间里取出get_id属性
此时你在测试里修改utils.get_id,是直接修改了模块对象本身的属性,而car模块里的utils变量一直指向这个模块对象,所以setup调用时会拿到替换后的Mock对象。
验证方式
可以在测试代码里加两行打印验证:
# 第一种导入方式下,两者地址不同 print(id(utils.get_id)) print(id(car.get_id)) # 第二种导入方式下,两者地址会同步变化 print(id(utils.get_id)) print(id(car.utils.get_id))
内容的提问来源于stack exchange,提问作者ningelsohn
相关产品推荐
相关产品推荐

