Further if it did your statement would look like:
with (open('file0') as file0, open('file1') as file1): pass
Which means that to simulate that behaviour you would actually want to indent like so:
with open('file0') as file0, \ open('file1') as file1: pass
I’m a little surprised by how you don’t see that the point is that the two open
s are aligned in the first example and not in the second. I actually want to indent like so:
with open('file0') as file0, \
open('file1') as file1:
pass
Notice the aligned expressions (the open
function calls in this example), this is visually pleasing.
And further the initial examples all show that pep8’s current behaviour is correct. It says you may indent to other indentation levels but that doesn’t mean the former examples are to be thrown out.
In that case shouldn’t E126 instead be a W1 warning? W191 (indentation with tabs) is a warning, while it is specifically banned by PEP8. On the flip side, non-4-space continuation lines is explicitly allowed by PEP8 (though, as you say, the examples all follow 4-space indents), yet it is reported as an error.
I can see why you would want to keep pep8’s current behavior, but I think that if pep8 isn’t going to ignore it (which I still think it should), it should at least be reduced to a warning for consistency’s sake.
I would like one more chance to convince you that removing E126 is consistent with the PEP8 style guide.
Specifically, PEP8 says the following:
Use 4 spaces per indentation level.
Note that this applies to indentation levels (for suites), and not continuation lines, which is the subject of E126. Continuation lines are described thusly.
Continuation lines should align wrapped elements either vertically using Python’s implicit line joining inside parentheses, brackets and braces, or using a hanging indent [5]. When using a hanging indent the following considerations should be applied; there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line.
Here we see that there are two options:
- vertical alignment using implicit line joining in parentheses
- hanging indent
The first doesn’t apply in this situation, so let’s look at the second. PEP8 describes a hanging ident as indenting the lines after the first line further than the first line to distinguish it from the first line, and specifically states that the 4-space indentation rule does not apply to continuation lines. Again recall that continuation lines are not the same as regular indentation of code in suites.
Thus, the only error PEP8 should report for the indentation of continuation lines is if the continuation line is indented the same amount as the first line, and any other style «errors», if they are kept in pep8, should be reduced to warnings at most.
For lines that are too long (e.g. > 79 characters), you can use parentheses to group your conditions:
if (first_index < 0
or second_index > self._number_of_plates - 1
or condition2
and candition3):
raise ValueError
Note that any boolean conditions (or
, and
) should go at the start of the line before the condition.
In your case, there is a special rule because of the if (...)
construct:
When the conditional part of an if-statement is long enough to require
that it be written across multiple lines, it’s worth noting that the
combination of a two character keyword (i.e. if), plus a single space,
plus an opening parenthesis creates a natural 4-space indent for the
subsequent lines of the multiline conditional. This can produce a
visual conflict with the indented suite of code nested inside the
if-statement, which would also naturally be indented to 4 spaces. This
PEP takes no explicit position on how (or whether) to further visually
distinguish such conditional lines from the nested suite inside the
if-statement. Acceptable options in this situation include, but are
not limited to:
# No extra indentation.
if (this_is_one_thing and
that_is_another_thing):
do_something()
# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
that_is_another_thing):
# Since both conditions are true, we can frobnicate.
do_something()
# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
and that_is_another_thing):
do_something()
(Also see the discussion of whether to break before or after binary
operators below.)
Source: PEP 8 Style Guide
Translate the contents of the pycodestyle error together with the actual error code so that you can understand it to some extent.
The code is mostly taken from the Flake8 Rules.
The tab-and-line-end-space relationship has been arbitrarily converted/deleted, so the bad code may be meaningless, so just for reference.
E1
— Errors about indentation
E101
: Indentation contains mixed spaces and tabs
-
Indentation mixed with tabs and spaces
bad
classTab: deffunc(): pass
good
classTab: deffunc(): pass
E111
: Indentation is not a multiple of four
-
The indentation space is not a multiple of 4
E112
: Expected an indented block
-
There is no indentation where it should be indented
E113
: Unexpected indentation
-
Unexpected indentation exists
E114
: Indentation is not a multiple of four (comment)
-
Indentation spaces are not multiples of 4 (comments)
bad
deffunc(): # `pass` does nothing pass
good
deffunc(): # `pass` does nothing pass
E115
: Expected an indented block (comment)
-
There is no indentation where it should be indented (comment)
bad
deffunc(): # `pass` does nothing pass
good
deffunc(): # `pass` does nothing pass
E116
: Expected an indented block (comment)
-
Unexpected indentation exists (comment)
bad
# This is function deffunc(): pass
good
# This is function deffunc(): pass
E117
: over-indented
-
Indentation is too deep
E121
1, 2: Continuation line under-indented for hanging indent
-
Shallow hanging indentation in continuation line 3
bad
{ 'key1':'value', 'key2':'value', }
good
{ 'key1':'value', 'key2':'value', }
bad
print("Python",( "Rules"))
good
print("Python", ( "Rules"))
E122
2 : Continuation line missing indentation or outdented
-
The indentation of continuation line 3 is absent or the indentation level is above
bad
{ 'key1':'value', 'key2':'value', }
good
{ 'key1':'value', 'key2':'value', }
E123
1 : Closing bracket does not match indentation of opening bracket’s line
-
The closing parentheses do not match the indentation level of the open parentheses row
bad
{ 'key1':'value', 'key2':'value', }
good
{ 'key1':'value', 'key2':'value', }
bad
result=function_that_takes_arguments( 'a','b','c', 'd','e','f', )
good
result=function_that_takes_arguments( 'a','b','c', 'd','e','f', )
E124
2 : Closing bracket does not match visual indentation
-
The closing parentheses are not visually consistent
bad
result=function_that_takes_arguments('a','b','c', 'd','e','f', )
good
result=function_that_takes_arguments('a','b','c', 'd','e','f', )
E125
2 : Continuation line with same indent as next logical line
-
The indentation level of continuation line 3 is the same as the logical line that follows.
- If the continuation line has the same indentation as the logical line that follows, increase the indentation level of the continuation line even further
bad
ifuserisnotNoneanduser.is_adminor \\ user.name=='Grant': blah='yeahnah'
good
ifuserisnotNoneanduser.is_adminor \\ user.name=='Grant': blah='yeahnah'
E126
1,2 : Continuation line over-indented for hanging indent
-
The indentation of continuation line 3 is too deep
bad
{ 'key1':'value', 'key2':'value', }
good
{ 'key1':'value', 'key2':'value', }
E127
2 : Continuation line over-indented for visual indent
-
The indentation of continuation line 3 is deeper than the indentation for visual unification
bad
print("Python",("Hello", "World"))
good
print("Python",("Hello", "World"))
E128
2 : Continuation line under-indented for visual indent
-
The indentation of continuation line 3 is shallower than the indentation for visual unification
bad
print("Python",("Hello", "World"))
good
print("Python",("Hello", "World"))
E129
2 : Visually indented line with same indent as next logical line
-
The indentation for visual unification is at the same indentation level as the logical line that follows
bad
if(row<0ormodule_count<=rowor col<0ormodule_count<=col): raiseException("%s,%s - %s"%(row,col,self.moduleCount))
good
if(row<0ormodule_count<=rowor col<0ormodule_count<=col): raiseException("%s,%s - %s"%(row,col,self.moduleCount))
E131
2 : Continuation line unaligned for hanging indent
-
The hanging indentation of continuation line 3 is not aligned
bad
{ "key1":"value", "key2":"value value value" "value", }
good
{ "key1":"value", "key2":"value value value" "value", }
E133
1 : Closing bracket is missing indentation
-
There is no indentation in closing parentheses
(only occurs when the option--hang-closing
is used)bad
my_list=[ 1,2,3, 4,5,6, ]
good
my_list=[ 1,2,3, 4,5,6, ]
E131
2 : Continuation line unaligned for hanging indent
-
The hanging indentation of continuation line 3 is not aligned
bad
{ "key1":"value", "key2":"value value value" "value", }
good
{ "key1":"value", "key2":"value value value" "value", }
E2
— Errors about whitespace
E201
: Whitespace after ‘(‘
-
There is a space after the opening parentheses
bad
withopen('file.dat')asf: contents=f.read()
good
withopen('file.dat')asf: contents=f.read()
E202
: Whitespace before ‘)’
-
There is a space before the closing parentheses
bad
withopen('file.dat')asf: contents=f.read()
good
withopen('file.dat')asf: contents=f.read()
E203
: Whitespace before ‘:’
-
There is a space before the colon
bad
withopen('file.dat')asf: contents=f.read()
good
withopen('file.dat')asf: contents=f.read()
E211
: Whitespace before ‘(‘
-
There is a space before the opening parentheses
bad
withopen('file.dat')asf: contents=f.read()
good
withopen('file.dat')asf: contents=f.read()
E221
: Multiple spaces before operator
-
Multiple spaces before the operator
E222
: Multiple spaces before operator
-
Multiple spaces after the operator
E223
: tab before operator
-
Tab character precedes operator
E224
: tab after operator
-
Operator followed by a tab character
E225
: Missing whitespace around operator
-
There are no spaces before or after the operator
bad
ifage>15: print('Can drive')
good
ifage>15: print('Can drive')
E226
1 : Missing whitespace around arithmetic operator
-
There are no spaces before or after the arithmetic operator (
+
, ,-
/
, )*
E227
: Missing whitespace around bitwise or shift operator
-
There are no spaces before or after the bitwise or shift operator (
<<
,>>
, , ,&
|
)^
E228
: Missing whitespace around modulo operator
-
There are no spaces before or after the modulus operator (
%
)
E231
: Missing whitespace after ‘,’, ‘;’, or ‘:’
-
,
,;
,:
There are no spaces before or after
E241
1 : Multiple spaces after ‘,’
-
,
followed by multiple spaces
E242
1 : Tab after ‘,’
-
,
followed by a tab character
E251
: Unexpected spaces around keyword / parameter equals
-
There are spaces before and after the
=
function definitionbad
deffunc(key1='val1', key2='val2'): returnkey1,key2
good
deffunc(key1='val1', key2='val2'): returnkey1,key2
E261
: At least two spaces before inline comment
-
At least two spaces are required before inline comments
bad
defprint_name(self): print(self.name)# This comment needs an extra space
good
defprint_name(self): print(self.name) # Comment is correct now
E262
: Inline comment should start with ‘# ‘
-
Inline comments must be followed by a
#
spacebad
defprint_name(self): print(self.name) #This comment needs a space
good
defprint_name(self): print(self.name) # Comment is correct now
E265
: Block comment should start with ‘# ‘
-
Block comments should
#
begin withbad
#This comment needs a space defprint_name(self): print(self.name)
good
# Comment is correct now defprint_name(self): print(self.name)
E266
: Too many leading ‘#’ for block comment
-
Too many block comments to start
#
bad
# Prints hello print('hello')
good
# Prints hello print('hello')
E271
: Multiple spaces after keyword
-
Multiple spaces after a keyword
E272
: Multiple spaces before keyword
-
Multiple spaces before a keyword
bad
deffunc(): if1 in[1,2,3]: print('yep!')
good
deffunc(): if1in[1,2,3]: print('yep!')
E273
: Tab after keyword
-
A keyword is followed by a tab character
E274
: Tab before keyword
-
A tab character precedes the keyword
bad
deffunc(): if1 in[1,2,3]: print('yep!')
good
deffunc(): if1in[1,2,3]: print('yep!')
E275
: Missing whitespace after keyword
-
No whitespace after keywords
bad
fromcollectionsimport(namedtuple,defaultdict)
good
fromcollectionsimport(namedtuple,defaultdict)
E3
— Error about empty lines
E301
: Expected 1 blank line, found 0
-
Need one blank line between the methods of the class
bad
classMyClass(object): deffunc1(): pass deffunc2(): pass
good
classMyClass(object): deffunc1(): pass deffunc2(): pass
E302
: Expected 2 blank lines, found 0
-
Need 2 blank lines between function and class
bad
deffunc1(): pass deffunc2(): pass
good
deffunc1(): pass deffunc2(): pass
E303
: Too many blank lines (3)
-
Too many blank lines
bad
deffunc1(): pass deffunc2(): pass
good
deffunc1(): pass deffunc2(): pass
E304
: Blank lines found after function decorator
-
There is a blank line after the function decorator
bad
classUser(object): @property defname(self): pass
good
classUser(object): @property defname(self): pass
## E305
: Expected 2 blank lines after end of function or class
* Two blank lines are required after the function or class ends
```python:bad
class User(object):
pass
user = User()
```
```python:good
class User(object):
pass
user = User()
```
E4
— Error with Import
E401
: Multiple imports on one line
-
Multiple imports are done in one row
good
importcollections importos importsys
E402
: Module level import not at top of file
-
Module-level imports occur outside the beginning of the file
bad
importlocale locale.setlocale(locale.LC_ALL,'en_US.UTF-8') importsys
good
importlocale importsys locale.setlocale(locale.LC_ALL,'en_US.UTF-8')
E5
— Error with line length
E501
2 : Line to long ((length) > 79 characters)
- Too many characters per line
- Recommended maximum number of characters is 79
- It is common to change to 100 or 120 characters
E502
: The backslash is redundant between brackets
-
Redundant backslashes in parentheses
bad
print('Four score and seven years ago our fathers brought '\\ 'forth, upon this continent, a new nation, conceived '\\ 'in liberty, and dedicated to the proposition that '\\ '"all men are created equal."')
good
print('Four score and seven years ago our fathers brought ' 'forth, upon this continent, a new nation, conceived ' 'in liberty, and dedicated to the proposition that ' '"all men are created equal."')
E7
— Error with statement
E701
: Multiple statements on one line (colon)
-
Multiple statements exist on a single line(
:
)
E702
: Multiple statements on one line (semicolon)
-
Multiple statements exist on a single line(
;
)bad
fromgeventimportmonkey;monkey.patch_all()
good
fromgeventimportmonkey monkey.patch_all()
E703
: Statement ends with a semicolon
-
The statement ends with a semicolon
E704
1 : Multiple statements on one line (def)
-
Multiple statements in a function definition are made on a single line
E711
2 : Comparison to none should be ‘if cond is none:’
-
Comparing singleton objects such as True, False, and None by equality rather than identity
bad
ifvar!=True: print("var is not equal to True") ifvar==None: print("var is equal to None")
good
ifvarisnotTrue print("var is not True") ifvarisNone print("var is None")
E712
2 : Comparison to true should be ‘if cond is true:’ or ‘if cond:’
-
True
and compare using the equality operatorbad
x=True ifx==True: print('True!')
good
x=True ifxisTrue: print('True!') # or simply: ifx: print('True!')
E713
: Test for membership should be ‘not in’
-
The negation of the result of is
in
used to verify the elementbad
my_list=[1,2,3] ifnotnuminmy_list: print(num)
good
my_list=[1,2,3] ifnumnotinmy_list: print(num)
E714
: Test for object identity should be ‘is not’
-
The negation of the result of is used to verify the identity of an
is
objectbad
ifnotuserisNone: print(user.name)
good
ifuserisnotNone: print(user.name)
E721
2 : Do not compare types, use ‘isinstance()’
-
Not using to
isinstance()
compare typesbad
iftype(user)==User: print(user.name)
good
ifisinstance(user,User): print(user.name)
E722
: Do not use bare except, specify exception instead
-
You do not specify an exception class when you catch an exception
bad
try: func() except: print("error")
good
try: func() exceptException: print("error")
E731
: Do not assign a lambda expression, use a def
-
Assigning a lambda expression to a variable
bad
root=lambdafolder_name:os.path.join(BASE_DIR,folder_name)
good
defroot(folder_name): returnos.path.join(BASE_DIR,folder_name)
E741
: Do not use variables named ‘l’, ‘O’, or ‘I’
-
l
You are using confusing variable names such as , , ,O
I
E742
: Do not define classes named ‘l’, ‘O’, or ‘I’
-
l
You are using confusing class names such as , , ,O
I
good
classIcon: deffunc(): pass
E743
: Do not define functions named ‘l’, ‘O’, or ‘I’
-
l
You are using confusing function names such as , , ,O
I
E9
— Runtime error
E901
: SyntaxError or IndentationError
- Syntax or indentation errors
E902
: IOError
- I/O error
W1
— Warnings about indentation
W191
: Indentation contains tabs
-
There are lines that are indented in the tab
W2
— Whitespace warning
W291
: Trailing whitespace
-
There is white space at the end of the line
W292
: No newline at end of file
-
there is no newline at the end of the file
W293
: Blank line contains whitespace
-
There is a blank space or tab on a blank line
bad
deffirst_func(): pass # This line contains four spaces defsecond_func(): pass
good
deffirst_func(): pass defsecond_func(): pass
W3
— Warning about blank lines
W391
: Blank line at end of file
-
there are multiple blank lines at the end of the file
W5
— Line break warnings
W503
1 : Line break occurred before a binary operator
-
A newline appears before the binary operator
- Currently deprecated,
W504
and exclusive relationship
bad
income=(gross_wages +taxable_interest)
good
income=(gross_wages+ taxable_interest)
- Currently deprecated,
W504
1 : Line break occurred after a binary operator
-
There is a newline after the binary operator
-
W503
and exclusive relationships
bad
income=(gross_wages+ taxable_interest)
good
income=(gross_wages +taxable_interest)
-
W505
1 2 : Doc line too long ((length) > 79 characters)
-
Too many characters per line in a comment or docstring
- 79 characters is the standard, but in flake8 you will not be warned if you do not give a
max-doc-length
value of
bad
deffunc(): """ Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing """ pass
good
deffunc(): """ Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing """ pass
- 79 characters is the standard, but in flake8 you will not be warned if you do not give a
W6
— Warnings about deprecation syntax
W601
: .has_key() is deprecated, use ‘in’
-
.has_key()
Using Methodsbad
{'key':'value'}.has_key('key')
W602
: Deprecated form of raising exception
-
Raising an exception in the deprecated form (
raise Exception, message
)bad
defcan_drive(age): ifage<16: raiseValueError,'Not old enough to drive' returnTrue
good
defcan_drive(age): ifage<16: raiseValueError('Not old enough to drive') returnTrue
W603
: ‘<>’ is deprecated, use ‘!=’
-
Using for non-equivalent
<>
comparisons
W604
: Backticks are deprecated, use ‘repr()’
-
Trying to string an object with backticks, deprecated in Python3
good
obj=MyObj() print(repr(obj))
W605
: invalid escape sequence ‘x’
-
Using an invalid escape sequence
- Any combination of backslash and value is considered an escape sequence
W606
: ‘async’ and ‘await’ are reserved keywords starting with Python 3.7
-
It uses and
async
,await
which are reserved words since Python 3.7
Having a consistent code style for a project is important as it allows
developers to code correctly without thinking too much about it. It makes code
easier to read, maintain and after becomming used to the style also
easier to write.
Most of the time, it is not too important which standards to follow, but to
decide in the team which ones you want to have and follow those consistently.
To cite from PEP8:
A style guide is about consistency. Consistency with [PEP8] is important.
Consistency within a project is more important. Consistency within one module
or function is the most important.
Python has standards for general coding as well as for docstrings.
General Coding
PEP8
The PEP8 was posted in July 2001
and got an update in 2013.
PyFlakes
PyFlakes is a very common tool to check
Python code for potential errors. I’ve added the codes to the long table below.
Docstrings
Python packages are usually documented on a function / class / method / package
level directly in the code. The stuff in docs/
is often only for building
HTML out of the Python code, organzinging things (e.g. which package to show
first) and a user manual.
There is PEP257 which defines some
basic stuff. Building on this, there are two docstring style guides which
cannot be combined: NumpyDoc an Google.
Tools like napoleon
in combination with Sphinx can automatically create nice docs of both of them.
NumpyDoc
See GitHub for the guide.
It looks as follows:
def get_meta(filepath, a_number, a_dict):
"""
Get meta-information of an image.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus.
Parameters
----------
filepath : str
Get metadata from this file
a_number : int
Some more details
a_dict : dict
Configuration
Returns
-------
meta : dict
Extracted meta information
Raises
------
IOError
File could not be read
"""
Google Style Docstrings
See Github
for the documentation.
It looks as follows:
def get_meta(filepath, a_number, a_dict):
"""Get meta-information of an image.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus.
Args:
filepath: Get metadata from this file.
a_number: Some more details.
a_dict: Configuration.
Returns:
Extracted meta information:
Raises:
IOError: File could not be read.
"""
SphinxDocString
It’s super ugly and I find it hard to read, but this docstring type is also out
there. SphinxDocString. They use reStructuredText:
def get_meta(filepath, a_number, a_dict):
"""
Get meta-information of an image.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus.
:param filepath: Get metadata from this file
:type filepath: str
:param a_number: Some more details
:type a_number: int
:param a_dict: Configuration
:type a_dict: dict
:returns: dict -- Extracted meta information
:raises: IOError
"""
McCabe code complexity
The McCabe complexity
measures how difficult it is to read your code. To quote from Wikipedia:
It is a quantitative measure of the number of linearly independent paths
through a program’s source code.
[…]
One of McCabe’s original applications was to limit the complexity of routines
during program development; he recommended that programmers should count the
complexity of the modules they are developing, and split them into smaller
modules whenever the cyclomatic complexity of the module exceeded 10.[2] This
practice was adopted by the NIST Structured Testing methodology, with an
observation that since McCabe’s original publication, the figure of 10 had
received substantial corroborating evidence, but that in some circumstances
it may be appropriate to relax the restriction and permit modules with a
complexity as high as 15.
I think McCabe complexity is one way to find spots where the could could be
improved for readability, but I’m not certain how often that actually works.
There is a mccabe pytest plugin.
Linters
Linters are tools for static code analysis. Static code analysis is the task of
analyzing a computer program without executing it. With executing the program,
it would be dynamic code analysis which is done by coverage testing tools.
Common Python linters are:
pycodestyle
which replacespep8
pydocstyle
flake8
pyrama
for checking package structureradon
: Measuring the code complexity
What you should forget
pylama
: Only wraps some other tools.
Use the pytest-plugins for those tools instead.
Don’t forget the Black Auto-Formatter. It is maintained by the Python Software Foundation, works well and has reasonable defaults. Makes you think and discuss less about formatting and solves many of the things linters complain about.
Error Codes
The following error codes are from pycodestyle
and
pydocstyle
.
I added to a couple why they exist and added a suggestion if I think you should take them
(from ✓✓ for a strong YES to ✘✘ for a strong NO). Please also have a
look at lintlyci.github.io/Flake8Rules
which gives a lot of good examples for those rules.
There are also two footnotes for some codes:
(*) In the default configuration, the checks E121, E123, E126, E133, E226,
E241, E242, E704, W503, W504 and W505 are ignored because they are not rules
unanimously accepted, and PEP 8 does not enforce them. Please note that if
the option –ignore=errors is used, the default configuration will be
overridden and ignore only the check(s) you skip. The check W503 is mutually
exclusive with check W504. The check E133 is mutually exclusive with check
E123. Use switch —hang-closing to report E133 instead of E123. Use switch
—max-doc-length=n to report W505.(^) These checks can be disabled at the line level using the # noqa special
comment. This possibility should be reserved for special cases.
Code | Meaning | Suggestion |
---|---|---|
E1 | Indentation | Indentation carries a meaning in Python — if code is in a block or not. |
E101 | indentation contains mixed spaces and tabs Why: When you mix spaces and tabs, you will get different indentation for different editor settings. |
✓✓ |
E111 | indentation is not a multiple of four Why: My guess is that 95% of all projects use 4 spaces — a single spaces is hard to read and more than four is something you don’t want to type that often |
✓ |
E112 | expected an indented block Why: A bug |
✓✓ |
E113 | unexpected indentation Why: A bug |
✓✓ |
E114 | indentation is not a multiple of four (comment) Why: Easily leads to bugs |
✓✓ |
E115 | expected an indented block (comment) Why: Easily leads to bugs |
✓✓ |
E116 | unexpected indentation (comment) Why: Easily leads to bugs |
✓✓ |
E121 (*^) | continuation line under-indented for hanging indent Why: Usual code style |
|
E122 (^) | continuation line missing indentation or outdented Why: Usual code style |
|
E123 (*) | closing bracket does not match indentation of opening bracket’s line Why: Readability |
✓ |
E124 (^) | closing bracket does not match visual indentation Why: Readability |
✓ |
E125 (^) | continuation line with same indent as next logical line Why: Readability |
✓ |
E126 (*^) | continuation line over-indented for hanging indent Why: Readability |
|
E127 (^) | continuation line over-indented for visual indent Why: Readability |
|
E128 (^) | continuation line under-indented for visual indent Why: Readability |
|
E129 (^) | visually indented line with same indent as next logical line Why: Readability |
|
E131 (^) | continuation line unaligned for hanging indent Why: Readability |
|
E133 (*) | closing bracket is missing indentation Why: Readability |
|
E2 | Whitespace | |
E201 | whitespace after ( Why: Usual code style |
|
E202 | whitespace before ) Why: Usual code style |
|
E203 | whitespace before
Why: Usual code style |
|
E211 | whitespace before ( |
|
E221 | multiple spaces before operator | |
E222 | multiple spaces after operator | |
E223 | tab before operator Why: Try to avoid tabs in Python |
✓✓ |
E224 | tab after operator Why: Try to avoid tabs in Python |
✓✓ |
E225 | missing whitespace around operator | |
E226 (*) | missing whitespace around arithmetic operator | |
E227 | missing whitespace around bitwise or shift operator | |
E228 | missing whitespace around modulo operator | |
E231 | missing whitespace after , , ; , or : |
|
E241 (*) | multiple spaces after , |
|
E242 (*) | tab after , Why: Try to avoid tabs in Python |
✓✓ |
E251 | unexpected spaces around keyword / parameter equals | |
E261 | at least two spaces before inline comment | |
E262 | inline comment should start with # |
|
E265 | block comment should start with # |
|
E266 | too many leading # for block comment |
|
E271 | multiple spaces after keyword Why: I can see the reason for one space … but many? |
✓✓ |
E272 | multiple spaces before keyword Why: I can see the reason for one space, but not for multiple |
✓✓ |
E273 | tab after keyword Why: Try to avoid tabs in Python |
✓✓ |
E274 | tab before keyword Why: Try to avoid tabs in Python |
✓✓ |
E275 | missing whitespace after keyword | |
E3 | Blank line | |
E301 | expected 1 blank line, found 0 | |
E302 | expected 2 blank lines, found 0 | |
E303 | too many blank lines (3) Why: Don’t make your code too stretched out. If you want to separate code, make a new module. |
✓✓ |
E304 | blank lines found after function decorator Why: This is confusing. A function decorator changes the function being decorated. If you separate them, I might miss that it is there. |
✓✓ |
E305 | expected 2 blank lines after end of function or class | |
E306 | expected 1 blank line before a nested definition | |
E4 | Import | |
E401 | multiple imports on one line Why: It’s more readable to have one import per line, you can structure them more easily and your editor can tell you which one you’re not using |
✓✓ |
E402 | module level import not at top of file Why: You should have all your imports at the top of your file. However, there could be other code as well in between imports. For example, setting the seed of random . |
✘ |
E5 | Line length | |
E501 (^) | line too long (> 79 characters) Why: See below. |
✓✓ |
E502 | the backslash is redundant between brackets | |
E7 | Statement | |
E701 | multiple statements on one line (colon) | |
E702 | multiple statements on one line (semicolon) | |
E703 | statement ends with a semicolon Why: Likely unnecessary and due to a C / C++ / Java developer (trying to) write Python code. |
✓✓ |
E704 (*) | multiple statements on one line (def) | |
E711 (^) | comparison to None should be if cond is None: Why: Example |
✓✓ |
E712 (^) | comparison to True should be if cond is True: or if cond: Why: Because if cond is way easier to read |
✓✓ |
E713 | test for membership should be not in |
|
E714 | test for object identity should be is not |
|
E721 (^) | do not compare types, use isinstance() |
|
E722 | do not use bare except, specify exception instead | |
E731 | do not assign a lambda expression, use a def Why: Example, DRY |
|
E741 | do not use variables named l , O , or I Why: Those letters are hard to distinguish in some fonts. |
✓✓ |
E742 | do not define classes named l , O , or I Why: Those letters are hard to distinguish in some fonts. |
✓✓ |
E743 | do not define functions named l , O , or I Why: Those letters are hard to distinguish in some fonts. |
✓✓ |
E9 | Runtime | |
E901 | SyntaxError or IndentationError | |
E902 | IOError | |
W1 | Indentation warning | |
W191 | indentation contains tabs | ✓✓ |
W2 | Whitespace warning | |
W291 | trailing whitespace Why: It just adds noise to git diff |
✓✓ |
W292 | no newline at end of file Why: answer |
|
W293 | blank line contains whitespace Why: It just adds noise to git diff |
✓✓ |
W3 | Blank line warning | |
W391 | blank line at end of file | |
W5 | Line break warning | |
W503 (*) | line break before binary operator | |
W504 (*) | line break after binary operator | |
W505 (*^) | doc line too long (82 > 79 characters) | |
W6 | Deprecation warning | |
W601 | .has_key() is deprecated, use in |
✓✓ |
W602 | deprecated form of raising exception | |
W603 | <> is deprecated, use != |
✓✓ |
W604 | backticks are deprecated, use repr() |
✓✓ |
W605 | invalid escape sequence x |
|
W606 | async and await are reserved keywords starting with Python 3.7 |
|
F4 | Flake8 module import | |
F401 | module imported but unused Why: Might keep unnecessary dependencies |
|
F402 | import module from line N shadowed by loop variable Why: Potential bug. |
✓✓ |
F403 | from module import * used; unable to detect undefined names |
|
F404 | future import(s) name after other statements | |
F8 | Flake8 name errors | |
F811 | redefinition of unused name from line N Why: Potentially unused code. |
|
F812 | list comprehension redefines name from line N | |
F821 | undefined name name | |
F822 | undefined name name in __all__ | |
F823 | local variable name … referenced before assignment | |
F831 | duplicate argument name in function definition | |
F841 | local variable name is assigned to but never used | |
N8 | Naming conventions | |
N801 | class names should use CapWords convention | ✓✓ |
N802 | function name should be lowercase | ✓✓ |
N803 | argument name should be lowercase | ✓✓ |
N804 | first argument of a classmethod should be named cls |
✓✓ |
N805 | first argument of a method should be named self |
✓✓ |
N806 | variable in function should be lowercase | ✓✓ |
N807 | function name should not start or end with __ |
|
N811 | constant imported as non constant | |
N812 | lowercase imported as non lowercase | |
N813 | camelcase imported as lowercase | |
N814 | camelcase imported as constant | |
D1 | Missing Docstrings | |
D100 | Missing docstring in public module | |
D101 | Missing docstring in public class | |
D102 | Missing docstring in public method | |
D103 | Missing docstring in public function | |
D104 | Missing docstring in public package | |
D105 | Missing docstring in magic method | |
D2 | Whitespace Issues | |
D200 | One-line docstring should fit on one line with quotes | |
D201 | No blank lines allowed before function docstring | |
D202 | No blank lines allowed after function docstring | |
D203 | 1 blank line required before class docstring | |
D204 | 1 blank line required after class docstring | |
D205 | 1 blank line required between summary line and description | |
D206 | Docstring should be indented with spaces, not tabs | |
D207 | Docstring is under-indented | |
D208 | Docstring is over-indented | |
D209 | Multi-line docstring closing quotes should be on a separate line | |
D210 | No whitespaces allowed surrounding docstring text | |
D211 | No blank lines allowed before class docstring | |
D212 | Multi-line docstring summary should start at the first line | |
D213 | Multi-line docstring summary should start at the second line | |
D3 | Quotes Issues | |
D300 | Use “”“triple double quotes”“” | |
D301 | Use r”“” if any backslashes in a docstring | |
D302 | Use u”“” for Unicode docstrings | |
D4 | Docstring Content Issues | |
D400 | First line should end with a period | |
D401 | First line should be in imperative mood | |
D402 | First line should not be the functions signature | |
D403 | First word of the first line should be properly capitalized |
Editor Support
You should let your editor do as many automatic formatting changes as you can.
- Sublime Text: Python Flake8 Lint (tested, works fine) and Auto PEP8 (not tested)
- Spyder: Auto PEP8 (not tested)
Notes on Details
Maximum Line Length
You might consider a maximum line lenght of 80 characters too extreme /
outdated.
Well, please have a look how a 3-way merge would look like on your machine. This
is how it looks like on mine:
And now look at files with 100 characters:
Sure, you can still do it. But for sure it also is less comfortable.
Let’s see how famous projects do it (code on GitHub):
Project | 95%-line length | 99%-line length | 100%-line length |
---|---|---|---|
numpy | 75 | 80 | 589 |
scipy | 76 | 83 | 5223 |
pandas | 74 | 79 | 801 |
Pillow | 73 | 80 | 185 |
sqlalchemy | 73 | 78 | 144 |
requests | 77 | 92 | 172 |
cpython | 75 | 81 | 1182 |
As you can see, all projects try to be below 79 characters per line. They
only break it for tests and documentation. Not for code. While I admit there
are some cases where you will get above the 79 character threshold, in
most cases it just means that you should change the way you wrote your code.
I’ve often seen it when you have many nested loops or conditions.
Another argument against longer line lengths is readability. Long lines are
just harder to read. Newspapers could also have way longer lines and less
columns. But they don’t do that. Websites also make columns. Let’s look at the
number of characters in a line for a couple:
Website | Category | Characters |
---|---|---|
Focus.de | News | 70 |
washingtonpost.com | News | 99 |
Sueddeutsche.de | News | 68 |
Medium.com | Blog posts | 73 |