Skip to content

unnecessary-map (C417)

Added in v0.0.74 · Related issues · View source

Derived from the flake8-comprehensions linter.

Fix is sometimes available.

What it does

Checks for unnecessary map() calls with lambda functions.

Why is this bad?

Using map(func, iterable) when func is a lambda is slower than using a generator expression or a comprehension, as the latter approach avoids the function call overhead, in addition to being more readable.

This rule also applies to map() calls within list(), set(), and dict() calls. For example:

  • Instead of list(map(lambda num: num * 2, nums)), use [num * 2 for num in nums].
  • Instead of set(map(lambda num: num % 2 == 0, nums)), use {num % 2 == 0 for num in nums}.
  • Instead of dict(map(lambda v: (v, v ** 2), values)), use {v: v ** 2 for v in values}.

Example

map(lambda x: x + 1, iterable)

Use instead:

(x + 1 for x in iterable)

Known problems

A map object and a generator expression are not interchangeable when the mapped expression raises. Once an exception propagates out of a generator, the generator is closed, so every later next() call raises StopIteration. A map object is not closed, so iteration can resume after the error:

values = ["0", "x", "2"]

m = map(lambda v: int(v), values)
next(m)  # 0
next(m)  # raises ValueError
next(m)  # 2

g = (int(v) for v in values)
next(g)  # 0
next(g)  # raises ValueError
next(g)  # raises StopIteration

Ruff cannot tell whether a caller relies on this difference, so the diagnostic is still reported in such cases.

Fix safety

This rule's fix is marked as unsafe because it can change how errors propagate out of the resulting iterator, as described above. It may also drop comments when rewriting the call.