flake8-comprehensions
A flake8 plugin that helps you write better list/set/dict comprehensions.
Requirements
Python 3.7 to 3.12 supported.
Installation
First, install with pip
:
python -m pip install flake8-comprehensions
Second, if you define Flake8’s select
setting, add the C4
prefix to it.
Otherwise, the plugin should be active by default.
Linting a Django project? Check out my book Boost Your Django DX which covers Flake8 and many other code quality tools.
Rules
<list/set/dict>
comprehension.
C400-402: Unnecessary generator - rewrite as a Rules:
- C400 Unnecessary generator - rewrite as a list comprehension.
- C401 Unnecessary generator - rewrite as a set comprehension.
- C402 Unnecessary generator - rewrite as a dict comprehension.
It's unnecessary to use list
, set
, or dict
around a generator expression, since there are equivalent comprehensions for these types.
For example:
- Rewrite
list(f(x) for x in foo)
as[f(x) for x in foo]
- Rewrite
set(f(x) for x in foo)
as{f(x) for x in foo}
- Rewrite
dict((x, f(x)) for x in foo)
as{x: f(x) for x in foo}
<set/dict>
comprehension.
C403-404: Unnecessary list comprehension - rewrite as a Rules:
- C403 Unnecessary list comprehension - rewrite as a set comprehension.
- C404 Unnecessary list comprehension - rewrite as a dict comprehension.
It's unnecessary to use a list comprehension inside a call to set
or dict
, since there are equivalent comprehensions for these types.
For example:
- Rewrite
set([f(x) for x in foo])
as{f(x) for x in foo}
- Rewrite
dict([(x, f(x)) for x in foo])
as{x: f(x) for x in foo}
<list/tuple>
literal - rewrite as a <set/dict>
literal.
C405-406: Unnecessary - C405 Unnecessary
<list/tuple>
literal - rewrite as a set literal. - C406 Unnecessary
<list/tuple>
literal - rewrite as a dict literal.
It's unnecessary to use a list or tuple literal within a call to set
or dict
.
For example:
- Rewrite
set([1, 2])
as{1, 2}
- Rewrite
set((1, 2))
as{1, 2}
- Rewrite
set([])
asset()
- Rewrite
dict([(1, 2)])
as{1: 2}
- Rewrite
dict(((1, 2),))
as{1: 2}
- Rewrite
dict([])
as{}
<dict/list>
comprehension - <builtin>
can take a generator
C407: Unnecessary This rule was dropped in version 3.4.0, because it promoted an increase in laziness which could lead to bugs.
<dict/list/tuple>
call - rewrite as a literal.
C408: Unnecessary It's slower to call e.g. dict()
than using the empty literal, because the name dict
must be looked up in the global scope in case it has been rebound.
Same for the other two basic types here.
For example:
- Rewrite
dict()
as{}
- Rewrite
dict(a=1, b=2)
as{"a": 1, "b": 2}
- Rewrite
list()
as[]
- Rewrite
tuple()
as()
<list/tuple>
passed to <list/tuple>
() - <advice>
.
C409-410: Unnecessary Rules:
- C409 Unnecessary
<list/tuple>
passed to tuple() -<advice>
. - C410 Unnecessary list passed to list() -
<advice>
.
Where <advice>
is either:
- remove the outer call to
<list/tuple>
() - rewrite as a
<list/tuple>
literal
It's unnecessary to use a list or tuple literal within a call to list
or tuple
, since there is literal syntax for these types.
For example:
- Rewrite
tuple([1, 2])
as(1, 2)
- Rewrite
tuple((1, 2))
as(1, 2)
- Rewrite
tuple([])
as()
- Rewrite
list([1, 2])
as[1, 2]
- Rewrite
list((1, 2))
as[1, 2]
- Rewrite
list([])
as[]
C411: Unnecessary list call - remove the outer call to list().
It's unnecessary to use a list
around a list comprehension, since it is equivalent without it.
For example:
- Rewrite
list([f(x) for x in foo])
as[f(x) for x in foo]
<dict/list/set>
comprehension - 'in' can take a generator.
C412: Unnecessary This rule was dropped in version 3.4.0, because it promoted an increase in laziness which could lead to bugs.
<list/reversed>
call around sorted().
C413: Unnecessary It's unnecessary to use list()
around sorted()
as it already returns a list.
It is also unnecessary to use reversed()
around sorted()
as the latter has a reverse
argument.
For example:
- Rewrite
list(sorted([2, 3, 1]))
assorted([2, 3, 1])
- Rewrite
reversed(sorted([2, 3, 1]))
assorted([2, 3, 1], reverse=True)
- Rewrite
reversed(sorted([2, 3, 1], reverse=True))
assorted([2, 3, 1])
<list/reversed/set/sorted/tuple>
call within <list/set/sorted/tuple>
().
C414: Unnecessary It's unnecessary to double-cast or double-process iterables by wrapping the listed functions within list
/set
/sorted
/tuple
.
For example:
- Rewrite
list(list(iterable))
aslist(iterable)
- Rewrite
list(tuple(iterable))
aslist(iterable)
- Rewrite
tuple(list(iterable))
astuple(iterable)
- Rewrite
tuple(tuple(iterable))
astuple(iterable)
- Rewrite
set(set(iterable))
asset(iterable)
- Rewrite
set(list(iterable))
asset(iterable)
- Rewrite
set(tuple(iterable))
asset(iterable)
- Rewrite
set(sorted(iterable))
asset(iterable)
- Rewrite
set(reversed(iterable))
asset(iterable)
- Rewrite
sorted(list(iterable))
assorted(iterable)
- Rewrite
sorted(tuple(iterable))
assorted(iterable)
- Rewrite
sorted(sorted(iterable))
assorted(iterable)
- Rewrite
sorted(reversed(iterable))
assorted(iterable)
<reversed/set/sorted>
().
C415: Unnecessary subscript reversal of iterable within It's unnecessary to reverse the order of an iterable when passing it into one of the listed functions will change the order again. For example:
- Rewrite
set(iterable[::-1])
asset(iterable)
- Rewrite
sorted(iterable)[::-1]
assorted(iterable, reverse=True)
- Rewrite
reversed(iterable[::-1])
asiterable
<dict/list/set>
comprehension - rewrite using <dict/list/set>
().
C416: Unnecessary It's unnecessary to use a dict/list/set comprehension to build a data structure if the elements are unchanged.
Wrap the iterable with dict()
, list()
, or set()
instead.
For example:
- Rewrite
{a: b for a, b in iterable}
asdict(iterable)
- Rewrite
[x for x in iterable]
aslist(iterable)
- Rewrite
{x for x in iterable}
asset(iterable)
map
usage - rewrite using a generator expression/<list/set/dict>
comprehension.
C417: Unnecessary map(func, iterable)
has great performance when func
is a built-in function, and it makes sense if your function already has a name.
But if your func is a lambda
, it’s faster to use a generator expression or a comprehension, as it avoids the function call overhead.
For example:
- Rewrite
map(lambda x: x + 1, iterable)
to(x + 1 for x in iterable)
- Rewrite
map(lambda item: get_id(item), items)
to(get_id(item) for item in items)
- Rewrite
list(map(lambda num: num * 2, nums))
to[num * 2 for num in nums]
- Rewrite
set(map(lambda num: num % 2 == 0, nums))
to{num % 2 == 0 for num in nums}
- Rewrite
dict(map(lambda v: (v, v ** 2), values))
to{v : v ** 2 for v in values}
<dict/dict comprehension>
passed to dict() - remove the outer call to dict()
C418: Unnecessary It's unnecessary to use a dict
around a dict literal or dict comprehension, since either syntax already constructs a dict.
For example:
- Rewrite
dict({})
as{}
- Rewrite
dict({"a": 1})
as{"a": 1}
<any/all>
() prevents short-circuiting - rewrite as a generator.
C419 Unnecessary list comprehension in Using a list comprehension inside a call to any()
/all()
prevents short-circuiting when a True
/ False
value is found.
The whole list will be constructed before calling any()
/all()
, potentially wasting work.part-way.
Rewrite to use a generator expression, which can stop part way.
For example:
- Rewrite
all([condition(x) for x in iterable])
asall(condition(x) for x in iterable)
- Rewrite
any([condition(x) for x in iterable])
asany(condition(x) for x in iterable)