Refactoring¶
These checks ensure that you don’t have patterns that can be refactored.
There are so many ways of doing the same thing in Python. Here we collect know patterns that can be rewritten into much easier or just more pythonic version.
Summary¶
Forbids to use |
|
Forbids to use |
|
Forbids to have simplifiable |
|
Forbids to use useless |
|
Forbids to use negated conditions together with |
|
Forbids to use nested |
|
Forbids to define useless proxy |
|
Forbids to have unpythonic zero-length compare. |
|
Forbids to use |
|
Forbids to nest ternary expressions in some places. |
|
Forbids to use |
|
Forbids to multiple |
|
Forbids to multiple |
|
Forbids to have implicit |
|
Forbids to use multiple equality compare with the same variable name. |
|
Forbids to use |
|
Forbids to compare types with |
|
Forbids to have useless starred expressions. |
|
Forbids to have implicit |
|
Forbids to have implicit |
|
Forbids to compare with explicit falsy constants. |
|
Forbids to compare values with constants using |
Refactoring opportunities¶
-
class
UselessLoopElseViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use
else
withoutbreak
in a loop.We use the same logic for
for
andwhile
loops.- Reasoning:
When there’s no
break
keyword in loop’s body it means thatelse
will always be called. This rule will reduce complexity, improve readability, and protect from possible errors.- Solution:
Refactor your
else
case logic to be inside the loop’s body. Or right after it.
Example:
# Correct: for letter in 'abc': if letter == 'b': break else: print('"b" is not found') for letter in 'abc': print(letter) print('always called') # Wrong: for letter in 'abc': print(letter) else: print('always called')
New in version 0.3.0.
Changed in version 0.11.0.
-
error_template
= 'Found `else` in a loop without `break`'¶
-
code
= 500¶
-
previous_codes
= {436}¶
-
class
UselessFinallyViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use
finally
intry
block withoutexcept
block.- Reasoning:
This rule will reduce complexity and improve readability.
- Solution:
Refactor your
try
logic. Replace thetry-finally
statement with awith
statement.
Example:
# Correct: with open("filename") as f: f.write(...) # Wrong: try: f = open("filename") f.write(...) finally: f.close()
New in version 0.3.0.
Changed in version 0.11.0.
-
error_template
= 'Found `finally` in `try` block without `except`'¶
-
code
= 501¶
-
previous_codes
= {437}¶
-
class
SimplifiableIfViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to have simplifiable
if
conditions.- Reasoning:
This complex construction can cause frustration among other developers. It is longer, more verbose, and more complex.
- Solution:
Use
bool()
to convert test values to boolean values. Or just leave it as it is in case when your test already returns a boolean value. Use can also usenot
keyword to switch boolean values.
Example:
# Correct: my_bool = bool(some_call()) other_value = 8 if some_call() else None # Wrong: my_bool = True if some_call() else False
We only check
if
nodes whereTrue
andFalse
values are used. We check bothif
nodes andif
expressions.New in version 0.7.0.
Changed in version 0.11.0.
-
error_template
= 'Found simplifiable `if` condition'¶
-
code
= 502¶
-
previous_codes
= {451}¶
-
class
UselessReturningElseViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use useless
else
cases in returning functions.We check single
if
statements that all containreturn
orraise
orbreak
statements with this rule. We do not checkif
statements withelif
cases.- Reasoning:
Using extra
else
creates a situation when the whole node could and should be dropped without any changes in logic. So, we prefer to have less code than more code.- Solution:
Remove useless
else
case.
Example:
# Correct: def some_function(): if some_call(): return 'yeap' return 'nope' # Wrong: def some_function(): if some_call(): raise ValueError('yeap') else: raise ValueError('nope')
New in version 0.7.0.
Changed in version 0.11.0.
-
error_template
= 'Found useless returning `else` statement'¶
-
code
= 503¶
-
previous_codes
= {457}¶
-
class
NegatedConditionsViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use negated conditions together with
else
clause.- Reasoning:
It easier to read and name regular conditions. Not negated ones.
- Solution:
Move actions from the negated
if
condition to theelse
condition.
Example:
# Correct: if some == 1: ... else: ... if not some: ... # Wrong: if not some: ... else: ...
New in version 0.8.0.
Changed in version 0.11.0.
-
error_template
= 'Found negated condition'¶
-
code
= 504¶
-
previous_codes
= {463}¶
-
class
NestedTryViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use nested
try
blocks.Notice, we check all possible slots for
try
block: 1. thetry
block itself 2. allexcept
cases 3.else
case 4. andfinally
case- Reasoning:
Nesting
try
blocks indicates that something really bad happens to your logic. Why does it require two separate exception handlers? It is a perfect case to refactor your code.- Solution:
Collapse two exception handlers together. Or create a separate function that will handle this second nested case.
Example:
# Wrong: try: try: ... except SomeException: ... except SomeOtherException: ... try: ... except SomeOtherException: try: ... except SomeException: ...
New in version 0.8.0.
Changed in version 0.11.0.
-
error_template
= 'Found nested `try` block'¶
-
code
= 505¶
-
previous_codes
= {464}¶
-
class
UselessLambdaViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to define useless proxy
lambda
expressions.- Reasoning:
Sometimes developers tend to overuse
lambda
expressions and they wrap code that can be passed as is, without extra wrapping. The code without extralambda
is easier to read and is more performant.- Solution:
Remove wrapping
lambda
declaration, use just the internal function.
Example:
# Correct: numbers = map(int, ['1', '2']) # Wrong: numbers = map(lambda string: int(string), ['1', '2'])
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found useless lambda declaration'¶
-
code
= 506¶
-
previous_codes
= {467}¶
-
class
UselessLenCompareViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to have unpythonic zero-length compare.
Note, that we allow to check arbitrary length, like
len(arr) == 3
.- Reasoning:
Python’s structures like dicts, lists, sets, and tuples all have
__bool__
method to checks their length. So, there’s no point in wrapping them intolen(...)
and checking that it is bigger that0
or less then1
, etc.- Solution:
Remove extra
len()
call.
Example:
# Correct: if some_array or not other_array or len(third_array) == 1: ... # Wrong: if len(some_array) > 0 or len(other_array) < 1: ...
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found useless `len()` compare'¶
-
code
= 507¶
-
previous_codes
= {468}¶
-
class
NotOperatorWithCompareViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use
not
with compare expressions.- Reasoning:
This version of
not
operator is unreadable.- Solution:
Refactor the expression without
not
operator. Change the compare signs.
Example:
# Correct: if x <= 5: ... # Wrong: if not x > 5: ...
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found incorrect `not` with compare usage'¶
-
code
= 508¶
-
previous_codes
= {470}¶
-
class
NestedTernaryViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to nest ternary expressions in some places.
Note, that we restrict to nest ternary expressions inside:
if
conditionsboolean and binary operations like
and
or+
unary operators
- Reasoning:
Nesting ternary in random places can lead to very hard debug and testing problems.
- Solution:
Refactor the ternary expression to be either a new variable, or nested
if
statement, or a new function.
Example:
# Correct: some = x if cond() else y # Wrong: if x if cond() else y: ...
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found incorrectly nested ternary'¶
-
code
= 509¶
-
previous_codes
= {472}¶
-
class
WrongInCompareTypeViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use
in
with static containers exceptset
nodes.We enforce people to use sets as a static containers. You can also use variables, calls, methods, etc. Dynamic values are not checked.
- Reasoning:
Using static
list
,tuple
, ordict
elements to check that some element is inside the container is a bad practice. Because we need to iterate all over the container to find the element. Sets are the best suit for this task. Moreover, it makes your code consistent.- Solution:
Use
set
elements or comprehensions to check that something is contained in a container.
Example:
# Correct: print(needle in {'one', 'two'}) # Wrong: print(needle in ['one', 'two'])
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found `in` used with a non-set container'¶
-
code
= 510¶
-
previous_codes
= {473}¶
-
class
UnmergedIsinstanceCallsViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to multiple
isinstance
calls with the same variable.- Reasoning:
The best practice is to use
isinstance
with tuple as the second argument, instead of multiple conditions joined withor
.- Solution:
Use tuple of types as the second argument.
Example:
# Correct: isinstance(some, (int, float)) # Wrong: isinstance(some, int) or isinstance(some, float)
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found separate `isinstance` calls that can be merged for: {0}'¶
-
code
= 511¶
-
previous_codes
= {474}¶
-
class
WrongIsinstanceWithTupleViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to multiple
isinstance
calls with tuples of a single item.- Reasoning:
There’s no need to use tuples with single elements. You can use single variables or tuples with multiple elements.
- Solution:
Use tuples with multiple elements or a single varaible.
Example:
# Correct: isinstance(some, (int, float)) isisntance(some, int) # Wrong: isinstance(some, (int, ))
See: https://docs.python.org/3/library/functions.html#isinstance
New in version 0.10.0.
Changed in version 0.11.0.
-
error_template
= 'Found `isinstance` call with a single element tuple'¶
-
code
= 512¶
-
previous_codes
= {475}¶
-
class
ImplicitElifViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.TokenizeViolation
Forbids to have implicit
elif
conditions.- Reasoning:
Nested
if
inelse
cases are bad for readability because of the nesting level.- Solution:
Use
elif
on the same level.
Example:
# Correct: if some: ... elif other: ... # Wrong: if some: ... else: if other: ...
New in version 0.12.0.
-
error_template
= 'Found implicit `elif` condition'¶
-
code
= 513¶
-
class
ImplicitInConditionViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use multiple equality compare with the same variable name.
- Reasoning:
Using double+ equality compare with
or
or double+ non-equality compare withand
indicates that you have implicitin
ornot in
condition. It is just hidden from you.- Solution:
Refactor compares to use
in
ornot in
clauses.
Example:
# Correct: print(some in {'first', 'second'}) print(some not in {'first', 'second'}) # Wrong: print(some == 'first' or some == 'second') print(some != 'first' and some != 'second')
New in version 0.10.0.
Changed in version 0.12.0.
-
code
= 514¶
-
error_template
= 'Found implicit `in` condition'¶
-
previous_codes
= {336}¶
-
class
OpenWithoutContextManagerViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to use
open()
with a context manager.- Reasoning:
When you
open()
something, you need to close it. When using a context manager - it is automatically done for you. When not using it - you might find yourself in a situation when file is not closed and is not accessable anymore.- Solution:
Refactor
open()
call to usewith
.
Example:
# Correct: with open(filename) as file_obj: ... # Wrong: file_obj = open(filename)
New in version 0.12.0.
-
code
= 515¶
-
error_template
= 'Found `open()` used without a context manager'¶
-
class
TypeCompareViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to compare types with
type()
function.- Reasoning:
When you compare types with
type()
function call it means that you break polymorphism and dissallow child classes of a node to work here. That’s incorrect.- Solution:
Use
isinstance
to compare types.
Example:
# Correct: print(something, type(something)) # Wrong: if type(something) == int: ...
New in version 0.12.0.
-
code
= 516¶
-
error_template
= 'Found `type()` used to compare types'¶
-
class
PointlessStarredViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to have useless starred expressions.
- Reasoning:
Using starred expression with constants is useless. This piece of code can be rewritten to be flat. Eg.:
print(*[1, 2, 3])
isprint(1, 2, 3)
.- Solution:
Refactor your code not to use starred expressions with
list
,dict
,tuple
, andset
constants. Use regular argument passing instead.
Example:
# Correct: my_list = [1, 2, 3, *other_iterable] # Wrong: print(*[1, 2, 3], **{{}})
New in version 0.12.0.
-
code
= 517¶
-
error_template
= 'Found pointless starred expression'¶
-
class
ImplicitEnumerateViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to have implicit
enumerate()
calls.- Reasoning:
Using
range(len(...))
is not pythonic. Python uses collection iterators, not index-based loops.- Solution:
Use
enumerate(...)
instead ofrange(len(...))
.
Example:
# Correct: for index, person in enumerate(people): ... # Wrong: for index in range(len(people)): ...
New in version 0.12.0.
-
code
= 518¶
-
error_template
= 'Found implicit `enumerate()` call'¶
-
class
ImplicitSumViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to have implicit
sum()
calls.When summing types different from numbers, you might need to provide the second argument to the
sum
function:sum([[1], [2], [3]], [])
You might also use
str.join
to join iterable of strings.- Reasoning:
Using
for
loops with+=
assign inside indicates that you iteratively sum things inside your collection. That’s whatsum()
builtin function does.- Solution:
Use
sum(...)
instead of a loop with+=
operation.
Example:
# Correct: sum_result = sum(get_elements()) # Wrong: sum_result = 0 for to_sum in get_elements(): sum_result += to_sum
See also
https://docs.python.org/3/library/functions.html#sum https://docs.python.org/3/library/stdtypes.html#str.join
New in version 0.12.0.
-
code
= 519¶
-
error_template
= 'Found implicit `sum()` call'¶
-
class
FalsyConstantCompareViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to compare with explicit falsy constants.
We allow to compare with falsy numbers, strings, booleans,
None
. We disallow complex constants like tuple, dicts, and lists.- Reasoning:
When comparing
something
with explicit falsy constants what we really mean isnot something
.- Solution:
Use
not
with your variable. Fix your data types.
Example:
# Correct: if not my_check: ... if some_other is None: ... if some_num == 0: ... # Wrong: if my_check == []: ...
New in version 0.12.0.
-
code
= 520¶
-
error_template
= 'Found compare with falsy constant'¶
-
class
WrongIsCompareViolation
(node, text=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolation
Forbids to compare values with constants using
is
oris not
.However, we allow to compare with
None
and booleans.- Reasoning:
is
compares might not do what you want them to do. Firstly, they check for the same object, not equality. Secondly, they behave unexpectedly even with the simple values like257
.- Solution:
Use
==
to compare with constants.
Example:
# Correct: if my_check == [1, 2, 3]: ... # Wrong: if my_check is [1, 2, 3]: ...
New in version 0.12.0.
-
code
= 521¶
-
error_template
= 'Found wrong `is` compare'¶