gpt4 book ai didi

python - 尝试使用返回 self 的 __iter__ 方法模拟迭代时出现 RecursionError

转载 作者:行者123 更新时间:2023-12-01 08:00:26 26 4
gpt4 key购买 nike

出于单元测试的目的,我创建了一个类,其实例是一个可迭代的,它将产生特定的序列,然后引发异常:

class Iter:
def __init__(self, seq):
self.seq = seq
self.pos = 0

def __next__(self):
if self.pos == len(self.seq):
raise Exception
value = self.seq[self.pos]
self.pos += 1
return value

def __iter__(self):
return self

这样:

for value in Iter((1, 2, 3)):
print(value)

将输出:

1
2
3
Traceback (most recent call last):
File "test.py", line 25, in <module>
for value in mocked_iterable:
File "test.py", line 11, in __next__
raise Exception
Exception

但是当MagicMock已经有一个应该做同样事情的side_effect属性时,为什么要重新发明轮子呢?根据 documentation ,side_effect 属性可以是一个可迭代的,它可以生成从模拟调用返回的值,也可以生成要引发的异常,因此它完全适合模仿上述类的目的。因此,我创建了一个 MagicMock 对象,并使其 __iter__ 方法返回对象本身,并使其 __next__ 方法具有所需的副作用顺序和异常:

from unittest.mock import MagicMock
mocked_iterable = MagicMock()
mocked_iterable.__iter__.return_value = mocked_iterable
mocked_iterable.__next__.side_effect = [1, 2, 3, Exception]
for value in mocked_iterable:
print(value)

但是,这会输出:

...
File "C:\Program Files (x86)\Python36-32\lib\unittest\mock.py", line 1005, in _mock_call
ret_val = effect(*args, **kwargs)
File "C:\Program Files (x86)\Python36-32\lib\unittest\mock.py", line 1793, in __iter__
return iter(ret_val)
File "C:\Program Files (x86)\Python36-32\lib\unittest\mock.py", line 939, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "C:\Program Files (x86)\Python36-32\lib\unittest\mock.py", line 944, in _mock_call
self.called = True
RecursionError: maximum recursion depth exceeded

但问题是,为什么会有递归呢?

我发现可以通过将自引用放入 __iter__side_effect 属性来解决这个“bug”:

mocked_iterable = MagicMock()
mocked_iterable.__iter__.side_effect = [mocked_iterable]
mocked_iterable.__next__.side_effect = [1, 2, 3, Exception]
for value in mocked_iterable:
print(value)

这正确输出:

1
2
3
Traceback (most recent call last):
File "test.py", line 6, in <module>
for value in mocked_iterable:
File "C:\Program Files (x86)\Python36-32\lib\unittest\mock.py", line 939, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "C:\Program Files (x86)\Python36-32\lib\unittest\mock.py", line 1000, in _mock_call
raise result
Exception

但是递归错误确实是一个错误,还是 mock 的一个功能,会带来意想不到的后果?

最佳答案

我同意这确实是一个错误。尽管这是一种边缘情况。

正如我们在源代码中看到的。如果 ret_val 已经是一个迭代器,mock 模块期望 iter(ret_val) 将返回未更改的迭代器。

嗯,确实如此,但仍然需要调用 ret_val__iter__ 方法。

关于python - 尝试使用返回 self 的 __iter__ 方法模拟迭代时出现 RecursionError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55768881/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com