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 |
|
Forbids to use implicit primitives in a form of |
|
Forbids unpythonic swap variables. |
|
Forbids to use misrefactored self assignment. |
|
Forbids comparisons where |
|
Forbids to use |
|
Forces using tuples as arguments for some functions. |
|
Forbids to use implicit |
|
Forbids to use implicit |
|
Forbids to use implicit negative indexes. |
Refactoring opportunities¶
-
class
UselessLoopElseViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use
elsewithoutbreakin a loop.We use the same logic for
forandwhileloops.- Reasoning:
When there’s no
breakkeyword in loop’s body it means thatelsewill always be called. This rule will reduce complexity, improve readability, and protect from possible errors.- Solution:
Refactor your
elsecase 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use
finallyintryblock withoutexceptblock.However, we allow to use
trywith justfinallyblock when function or method is decorated. Because we cannot control what is going on in this decorator. It might be@contextmanageror similar thing that requires this API.- Reasoning:
This rule will reduce complexity and improve readability.
- Solution:
Refactor your
trylogic. Replace thetry-finallystatement with awithstatement.
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.
Changed in version 0.14.0.
-
error_template= 'Found `finally` in `try` block without `except`'¶
-
code= 501¶
-
previous_codes= {437}¶
-
class
SimplifiableIfViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to have simplifiable
ifconditions.- 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 usenotkeyword 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
ifnodes whereTrueandFalsevalues are used. We check bothifnodes andifexpressions.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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use useless
elsecases in returning functions.We check single
ifstatements that all containreturnorraiseorbreakstatements with this rule. We do not checkifstatements withelifcases.- Reasoning:
Using extra
elsecreates 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
elsecase.
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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use negated conditions together with
elseclause.- Reasoning:
It easier to read and name regular conditions. Not negated ones.
- Solution:
Move actions from the negated
ifcondition to theelsecondition.
Example:
# Correct: if some == 1: ... else: ... if not some: ... if not some: ... elif other: ... # 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use nested
tryblocks.Notice, we check all possible slots for
tryblock: 1. thetryblock itself 2. allexceptcases 3.elsecase 4. andfinallycase- Reasoning:
Nesting
tryblocks 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to define useless proxy
lambdaexpressions.- Reasoning:
Sometimes developers tend to overuse
lambdaexpressions and they wrap code that can be passed as is, without extra wrapping. The code without extralambdais easier to read and is more performant.- Solution:
Remove wrapping
lambdadeclaration, 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids 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 that0or 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use
notwith compare expressions.- Reasoning:
This version of
notoperator is unreadable.- Solution:
Refactor the expression without
notoperator. 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to nest ternary expressions in some places.
Note, that we restrict to nest ternary expressions inside:
ifconditionsboolean and binary operations like
andor+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
ifstatement, 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use
inwith static containers exceptsetnodes.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, ordictelements 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
setelements 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.
Changed in version 0.14.0.
-
error_template= 'Found `in` used with a non-set container'¶
-
code= 510¶
-
previous_codes= {473}¶
-
class
UnmergedIsinstanceCallsViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to multiple
isinstancecalls with the same variable.- Reasoning:
The best practice is to use
isinstancewith 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to multiple
isinstancecalls 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)) isinstance(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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.TokenizeViolationForbids to have implicit
elifconditions.- Reasoning:
Nested
ifinelsecases are bad for readability because of the nesting level.- Solution:
Use
elifon 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use multiple equality compare with the same variable name.
- Reasoning:
Using double+ equality compare with
oror double+ non-equality compare withandindicates that you have implicitinornot incondition. It is just hidden from you.- Solution:
Refactor compares to use
inornot inclauses.
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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids 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
isinstanceto 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids 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, andsetconstants. 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to have implicit
sum()calls.When summing types different from numbers, you might need to provide the second argument to the
sumfunction:sum([[1], [2], [3]], [])You might also use
str.jointo join iterable of strings.- Reasoning:
Using
forloops 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids 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
somethingwith explicit falsy constants what we really mean isnot something.- Solution:
Use
notwith 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, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to compare values with constants using
isoris not.However, we allow to compare with
Noneand booleans.- Reasoning:
iscompares 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'¶
-
class
ImplicitPrimitiveViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use implicit primitives in a form of
lambdafunctions.- Reasoning:
When you use
lambdathat returns a primitive value and takes no arguments, it means that you should use a primitive type instead.- Solution:
Replace
lambdawithint,float,list, or any other primitive.
Example:
# Correct: defaultdict(int) # Wrong: defaultdict(lambda: 0)
New in version 0.13.0.
-
code= 522¶
-
error_template= 'Found implicit primitive in a form of `lambda`'¶
-
class
AlmostSwappedViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids unpythonic swap variables.
We check for
a = b; b = asequences.- Reasoning:
This looks like a failed attempt to swap.
- Solution:
Use standard way to swap two variables.
Example:
# Correct: a, b = b, a # Wrong: a = b b = a temp = a a = b b = temp
New in version 0.13.0.
-
error_template= 'Found incorrectly swapped variables'¶
-
code= 523¶
-
class
MisrefactoredAssignmentViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use misrefactored self assignment.
- Reasoning:
Self assignment does not need to have the same operand on the left hand side and on the right hand side.
- Solution:
Refactor you code to use multiple self assignments or fix your code.
Example:
# Correct: test += 1 test *= 2 # Wrong: test += test + 1
See
MATH_APPROXIMATE_CONSTANTSfor full list of math constants that we check for.New in version 0.13.0.
-
error_template= 'Found self assignment with refactored assignment'¶
-
code= 524¶
-
class
InCompareWithSingleItemContainerViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids comparisons where
inis compared with single item container.- Reasoning:
incomparison with a container which contains only one item looks like overhead and unneeded complexity.- Solution:
Refactor your code to use
==insteadin.
Example:
# Correct: a == 's' # Wrong: a in {'s'}
New in version 0.13.0.
-
error_template= 'Found wrong `in` compare with single item container'¶
-
code= 525¶
-
class
ImplicitYieldFromViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use
yieldinsideforloop instead ofyield from.- Reasoning:
It is known that
yield fromis a semantically identical to aforloop with ayieldinside. But, it is way more readable.- Solution:
Use
yield fromsome iterable directly instead iterating over it inside a loop andyieldit one by one.
Example:
# Correct: yield from some() yield from ( value[index:index + chunk_size] for index in range(0, len(value), chunk_size) ) # Wrong: for index in chunk: yield index
New in version 0.13.0.
-
error_template= 'Found implicit `yield from` usage'¶
-
code= 526¶
-
class
NotATupleArgumentViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForces using tuples as arguments for some functions.
- Reasoning:
For some functions, it is better to use tuples instead of another iterable types (list, sets,…) as arguments.
- Solution:
Use tuples as arguments.
Example:
# Correct: a = frozenset((2,)) # Wrong: a = frozenset([2])
See
TUPLE_ARGUMENTS_METHODSfor full list of methods that we check for.New in version 0.13.0.
-
error_template= 'Found not a tuple used as an argument'¶
-
code= 527¶
-
class
ImplicitItemsIteratorViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use implicit
.items()iterator.- Reasoning:
When iterating over collection it is easy to forget to use
.items()when you need to access both keys and values. So, when you access the iterable with the key inside aforloop, that’s a sign to refactor your code.- Solution:
Use
.items()with direct keys and values when you need them.
Example:
# Correct: for some_key, some_value in collection.items(): print(some_key, some_value) # Wrong: for some_key in collection: print(some_key, collection[some_key])
New in version 0.13.0.
-
error_template= 'Found implicit `.items()` usage'¶
-
code= 528¶
-
class
ImplicitDictGetViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use implicit
.get()dict method.- Reasoning:
When using
inwith a dict key it is hard to keep the code clean. It is more convinient to use.get()and check forNonelater.- Solution:
Use
.get()with the key you need. Check forNonein case you need it, or just act with the default value of the same type.
Example:
# Correct: value = collection.get(key) if value is not None: print(value) # Wrong: if key in collection: print(collection[key])
New in version 0.13.0.
-
error_template= 'Found implicit `.get()` dict usage'¶
-
code= 529¶
-
class
ImplicitNegativeIndexViolation(node, text=None, baseline=None)[source]¶ Bases:
wemake_python_styleguide.violations.base.ASTViolationForbids to use implicit negative indexes.
- Reasoning:
There’s no need in getting the length of an iterable and then having a negative offset, when you can specify negative indexes in the first place.
- Solution:
Use negative indexes.
Example:
# Correct: some_list[-1] # Wrong: some_list[len(some_list) - 1]
New in version 0.13.0.
-
error_template= 'Found implicit negative index'¶
-
code= 530¶