我试图为使用简单验证功能的函数编写测试。我的函数需要验证所有传入的参数。验证函数在出现问题时抛出AttributeError
,否则返回True。但是,当我映射validate
时,除非我执行其他操作,否则它不会起作用,例如使用all()
:
def my_function(a, b, c=None):
map(validate, (a, b, c)) # This doesn't fail validation (incorrect behavior)
all(map(validate, (a, b, c)) # This DOES fail validation (correct behavior)
# Some other stuff
我的单元测试是这样做的:
def test_my_function(self):
bad_id = 0
self.assertRaises(AttributeError, add_favorite, 10, bad_id)
这是我的验证功能:
def validate(identifier):
if identifier is None:
return True
elif not isinstance(identifier, int):
raise AttributeError("Identifier={0} not of type integer.".format(identifier))
elif not (identifier > 0):
raise AttributeError("Identifier={0} not an integer greater than zero.".format(identifier))
else:
return True
我很困惑,为什么map
似乎无法执行,除非我将其包装在其他内容中:我已经确认它不会通过调试运行测试来执行并看到它永远不会进入validate()
。 (我认为做出额外的工作没有意义......)根据documentation,似乎map 应该迭代这些参数并执行该函数。有人可以解释为什么它没有?
编辑:正确documentation表明map返回一个延迟评估的迭代器。
答案 0 :(得分:4)
在python 3.x中,map
创建一个可迭代的。 Iterables被懒惰地评估 - 也就是说,实际上只评估迭代的元素(例如循环遍历它们)。在您的示例中,由于您不会迭代任何值,因此不会评估任何值。但是,在any
的情况下,any
会迭代整个结果map
,因此整个事情都会得到评估。
它有点复杂,因为还有其他方法来评估迭代的部分而不迭代它们(例如使用next()
来评估并获得下一个项目),但是对于您的目的,这是足够接近。
所以这些得到评估:
all(map(validate, (a, b, c))
list(map(validate, (a, b, c)))
[_ for x in map(validate, (a, b, c))]
a = map(validate, (a, b, c);all(a)
b = map(validate, (a, b, c));list(b)
请注意,在最后两种情况下,在调用all(a)
或list(a)
之前不会评估iterable。这可能是代码后面,另一个函数和/或另一个模块中的许多行。
此外,迭代只能一次评估一个步骤。考虑这个例子:
for x in map(validate, (a, b, c)):
print(x)
它将在第一个项目上运行validate
,放入x,然后运行循环体。完成循环的第一次运行后,它才会评估第二项,然后再次遍历循环体,然后评估下一项,依此类推。如果中断循环,则不会评估剩余的项目。
这些不会被评估:
map(validate, (a, b, c)
a = map(validate, (a, b, c)
(_ for x in map(validate, (a, b, c)))