Line breaks should occur before the binary operator to keep all operators aligned.
This rule was changed on April 16th, 2016 in this commit. The tool is updated to recommend that line breaks should occur before the binary operator because it keeps all operators aligned. However older versions of tooling can still recommend the previous behaviour. See also W503.
Anti-pattern
income = (gross_wages +
taxable_interest)
Best practice
income = (gross_wages
+ taxable_interest)
Additional links
- https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator
Solution 1:[1]
If we consult the documentation on flake 8 we see:
Anti-pattern
Note: Despite being in the anti-pattern section, this will soon be
considered the best practice.income = (gross_wages + taxable_interest)
Best practice
Note: Despite being in the best practice section, this will soon be
considered an anti-pattern.income = (gross_wages + taxable_interest)
So the line break before the binary operator will be considered best practice.
The documentation for W504, advices the operator before the new line as best practice, without the given note:
Anti-pattern
income = (gross_wages + taxable_interest)
Best practice
income = (gross_wages + taxable_interest)
Solution 2:[2]
When in doubt, ask Black:
if (
this_is_one_thing
and that_is_another_thing
):
do_something()
For a long time, PEP-8 recommended breaking after a binary operator, but they have “recently” switched to the Donald-Knuth-approved break-before-binary-operator style.
Solution 3:[3]
instead and
or or
you can use all
or any
:
if all(
this_is_one_thing,
that_is_another_thing):
do_something()
Solution 4:[4]
Flake8 is one of the Python lints, and the full list of errors can be found useful to find anti-patterns and best practices for each specific error.
Configuraton:
- OS: Arch Linux
- pycodestyle version: 2.6.0
- Python version: 3.8.3
- Installation source: Arch Linux packages
W504 (line break after binary operator) shows up when the slash that indicates positional-only arguments (PEP 570) is followed by a newline. For example:
def really_long_name_for_a_function( very_long_argument_1, very_long_argument_2, / ): pass
pycodestyle thinks that the slash is a binary operator. I can, however, silence it using a comma after the slash, as follows:
def really_long_name_for_a_function( very_long_argument_1, very_long_argument_2, /, ): pass
I think this is an issue, as the slash isn’t a binary operator, and the comma seems like a workaround for arguments on a single line than good practice (at least in this case).
Troubleshooting
Actually, I’m not so much troubled, but I was wondering what everyone was doing and asked a question.
Which flake8 rule should I follow?
- line break before binary operatorflake8 (W503)
# bad
income = (gross_wages
+ taxable_interest)
# good
income = (gross_wages +
taxable_interest)
- line break after binary operatorflake8 (W504)
# bad
income = (gross_wages +
taxable_interest)
# good
income = (gross_wages
+ taxable_interest)
If i follow either one, you will ignore the other rule.
Which is the stronger rule?
Although there is a way of thinking that you can decide which one to protect, you will get lost in spite of what you can do.
I personally like this
income = (gross_wages
+ taxable_interest)
The reason is that you can see at a glance that the calculation continues from the previous line without looking beyond the line.
In the first place
If i have an opinion that it is not good to have a line break in the middle of the calculation, I would like to ask you why. . .
Reference site
https://lintlyci.github.io/Flake8Rules/rules/W503.html
https://lintlyci.github.io/Flake8Rules/rules/W504.html
Problem Description:
I keep getting:
W503 line break before binary operator
Please help me fix my code, as I can’t figure out what is wrong here:
def check_actionable(self, user_name, op, changes_table):
return any(user_name in row.inner_text() and row.query_selector(
self.OPS[op]) is not
None and row.query_selector(self.DISABLED) is not None for
row in changes_table)
Solution – 1
W503 rule and W504 rule of flake8 are conflicted to each other. I recommend you to add one of them into your .flake8
‘s ignore list.
W503: line break before binary operator
W504: line break after binary operator
ignore = D400,D300,D205,D200,D105,D100,D101,D103,D107,W503,E712
The below code is prettified:
def check_actionable(self, user_name, op, changes_table):
return any(user_name in row.inner_text() and
row.query_selector(self.OPS[op]) is not None and
row.query_selector(self.DISABLED) is not None for row in changes_table)
Some explanation on W503 and W504:
binary operator: +, -, /, and, or, …
To pass W503, your code should be like this:
x = (1
+ 2)
To pass W504, your code should be like this:
x = (1 +
2)
Solution – 2
the other (imo better) alternative to ignore
(which resets the default ignore list) is to use extend-ignore
by default both W503
and W504
are ignored (as they conflict and have flip-flopped historically). there are other rules which are ignored by default as well that you may want to preserve
extend-ignore = ABC123
ignore
on the other hand resets the ignore list removing the defaults
disclaimer: I’m the current flake8 maintainer