跳到内容

unnecessary-comprehension-in-call (C419)

Derived from the flake8-comprehensions linter. (源自 flake8-comprehensions linter。)

有时提供修复。

作用

检查传递给接受可迭代对象的内置函数的不必要的列表或集合推导式。

仅当内置函数不关心传递的可迭代对象中元素的重复时,集合推导式才算违规。

为什么这不好?

许多内置函数(此规则目前稳定版本涵盖 anyall预览版中涵盖 minmaxsum)接受任何可迭代对象,包括生成器。通过列表推导式构造临时列表是不必要的,并且浪费了大型可迭代对象的内存。

anyall 也可以短路迭代,从而节省大量时间。不必要的推导式强制对输入的可迭代对象进行完全迭代,放弃了短路的好处。例如,比较 all 与列表推导式的性能,以及在可能提前短路的情况下生成器的性能(快了近 40 倍)

In [1]: %timeit all([i for i in range(1000)])
8.14 µs ± 25.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [2]: %timeit all(i for i in range(1000))
212 ns ± 0.892 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

这种性能提升是由于短路造成的。如果必须遍历整个可迭代对象,则推导式版本甚至可能更快:列表分配开销不一定大于生成器开销。

应用此规则可以简化代码,通常可以节省内存,但在没有短路的情况下,它可能不会提高性能。(它甚至可能略微降低性能,尽管差异通常很小。)

示例

any([x.id for x in bar])
all([x.id for x in bar])
sum([x.val for x in bar])
min([x.val for x in bar])
max([x.val for x in bar])

建议改为

any(x.id for x in bar)
all(x.id for x in bar)
sum(x.val for x in bar)
min(x.val for x in bar)
max(x.val for x in bar)

修复安全性

此规则的修复被标记为不安全,因为它会在迭代具有副作用时更改代码的行为(由于惰性和短路)。在重写某些推导式时,此修复程序也可能会删除注释。