5 min guide to PEP8

Posted by Bob on Mon 02 January 2017 in Best practices

One of Guido's key insights is that code is read much more often than it is written. - PEP8

There should be one—and preferably only one—obvious way to do it. - The Zen of Python

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler

After Julian's two recent style posts on indentation and naming convention a nice follow-up is PEP8, the Style Guide for Python Code. Also a comment on Twitter caught my eye stating that even book authors do not always follow PEP8!

Why bother?

I think everybody writing code in Python should become familiar with PEP8 and use its guidelines rather sooner than later.

It leads to more readable code which saves brain cycles and better maintainable code (= fewer bug).

Also sharing a common coding style makes it easier to collaborate with others in the Python community.

Of course there can be exceptions to the rule, PEP8 states: "do not break backwards compatibility just to comply with this PEP!" - Raymond Hettinger did a great talk on this: Beyond PEP 8

Summary of the guidelines

A read that is aimed for '5 min' cannot have all, so I just summarize what I think is important, read the full spec for details:

  • Use 4 spaces per indentation level. Use spaces, not tabs. See our post for more on this, including recommended .vimrc settings. Overall watch your use of whitespace: this takes practice, but becomes habit/ automatic over time.

  • Limit all lines to a maximum of 79 characters. Usually I have a script.py and test_script.py open, vertically alligned (vi -O file1 file2), keeping lines short makes this very convenient.

  • Imports I) be as specific as possible with your imports:

    # don't do: 
    from time import *
    (unless needed, then use the __all__ mechanism to prevent exporting globals)
    # do:
    from time import time
    # or:
    import time
    # then prepends each method with module name: 
  • Imports II) absolute imports are recommended:

    from mypkg.sibling import example   
    # over
    from .sibling import example
  • Imports III) split imports in stdlib - third party - application/library specific. For example our twitter bot followed this convention:

    # stdlib
    import datetime
    import logging
    import time
    # pip installed
    import feedparser
    import tweepy
    # app modules
    from config import ...
  • Comments that contradict the code are worse than no comments, so keep them up2date. Use inline comments sparingly. Of course good code is mostly self-documenting.

  • Use docstrings, they are a great aid for auto-documenting your project with tools like Sphinx. Here is the recommended syntax:

    """Multi-line docstrings consist of a summary line just like a one-line docstring
    Followed by a blank line, followed by a more elaborate description. 
  • Naming:

    • Non-public methods and instance variables start with a leading underscore: _helper_method(), although not enforced by the compiler, the reader knows this is an internal method, not to be called from outside of the class.

    • If you need to use a Python keyword append an underscore: str_ = 'bob'

    • You probably want to avoid single-char variables all together, but if you use them never use these easily confused chars: 'l' (lowercase letter el), 'O' (uppercase letter oh), or 'I' (uppercase letter eye).

    • Use CapWords for class names.

    • Use short, all-lowercase names for modules.

    • Use lowercase and underscores for method names.

    • Constants are all uppercase, in our Twitter bot example: CONSUMER_KEY, CONSUMER_SECRET, etc.

  • Programming Recommendations has some great tips: use ''.join(list) instead of string concatenation which is slow, use str.startswith/endswith instead of slicing (or more generically don't re-invent the wheel), boolean checks don't need == True/False, be consistent in return statements (even if returning None, use return None, not just return).

    Interesting is the part on exceptions: two common mis-uses are putting too much in the try block, or catching exceptions that are too generic, so train yourself to use specific exceptions: 'except SomeError' instead of the catch-all 'except'.

    Another interesting best practice is checking booleans, newcomers usually check False like 'if len(somelist) == 0', the Pythonic way is to just to use the fact that non-empty values are implicitly True, so in this case you could just do: 'if not somelist'.

Tools to check for compliant PEP8

You can use pep8

$ pip install pep8

Our digest.py seemed compliant but let's make some edits to see this checker in action. I changed spaces from 4 to 2 in a method, mis-aligned a multi-line statement, and removed a whitespace before '='. Of course pep8 complains:

$ pep8 digest.py 
digest.py:24:3: E111 indentation is not a multiple of four
digest.py:25:3: E111 indentation is not a multiple of four
digest.py:26:3: E111 indentation is not a multiple of four
digest.py:50:18: E225 missing whitespace around operator
digest.py:54:80: E501 line too long (83 > 79 characters)

Another tool is flake8 which is "a wrapper around these tools: PyFlakes, pycodestyle and Ned Batchelder’s McCabe script". It also has a nice integration in Vim: it runs the checks and presents them in a split window with line numbers, pretty convenient!

flake 8 inside vim

Btw I got this split window pressing ,f which I find easier on a Mac than F7, you can create a shortcut like this in your .vimrc:

autocmd FileType python map <buffer> ,f :call Flake8()<CR>

Another linter is pylint but I have not used that. What is your favorite linter?

Wrapping it up

Always follow the PEP 8 style guide when writing Python code.

Therefor keep a copy of PEP8 at hand and review it often to ingrain its recommendations. It makes code cleaner and collaboration easier.

Using a linter tool is the best way to remind/ train yourself. Just google for plugins / integration with your favorite editor.

Any feedback, questions or experiences, use the comments below.

Keep Calm and Code in Python!

-- Bob

>>> next(PyBites)

Get our 'Become a Better Python Developer' cheat sheet sent straight to your inbox by signing up for our Newsletter: