Skip to content

unnecessary-comprehension-in-call (C419)

Derived from the flake8-comprehensions linter.

Fix is sometimes available.

What it does

Checks for unnecessary list or set comprehensions passed to builtin functions that take an iterable.

Set comprehensions are only a violation in the case where the builtin function does not care about duplication of elements in the passed iterable.

Why is this bad?

Many builtin functions (this rule currently covers any and all in stable, along with min, max, and sum in preview) accept any iterable, including a generator. Constructing a temporary list via list comprehension is unnecessary and wastes memory for large iterables.

any and all can also short-circuit iteration, saving a lot of time. The unnecessary comprehension forces a full iteration of the input iterable, giving up the benefits of short-circuiting. For example, compare the performance of all with a list comprehension against that of a generator in a case where an early short-circuit is possible (almost 40x faster):

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)

This performance improvement is due to short-circuiting. If the entire iterable has to be traversed, the comprehension version may even be a bit faster: list allocation overhead is not necessarily greater than generator overhead.

Applying this rule simplifies the code and will usually save memory, but in the absence of short-circuiting it may not improve performance. (It may even slightly regress performance, though the difference will usually be small.)

Examples

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])

Use instead:

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)

Fix safety

This rule's fix is marked as unsafe, as it can change the behavior of the code if the iteration has side effects (due to laziness and short-circuiting). The fix may also drop comments when rewriting some comprehensions.