Link Search Menu Expand Document

Python Coding Style Guidelines

Table of Contents

TL;DR

  • Follow PEP8
  • Keep line lengths under 99, but under 88 is better when possible
  • Use black, flake8, and isort

The Zen of Python

Python has a set of guiding principles that are built into the language itself. Literally. Open up a Python interpreter (by running python in your terminal) and type import this. Alternatively, you can look at PEP20.

Read through these wise words and take them to heart. They’re great advice for writing code (not just in Python), and for life in general. And if you ever need a reminder, you’re only one import away!

PEP8 - Style Guide for Python Code

Python provides official recommendations for style in the form of PEP8. We generally recommend following it as close as possible, but even PEP8 itself encourages developers to use their best judgement and ignore its guidelines from time to time. Give the document a read, it’s full of great ideas! But if you’re in a hurry, here are some of the most important parts to us:

Indentation

Tabs or Spaces

Tabs or Spaces? Wars have been fought over less. But in the interest of bringing peace to the galaxy, we defer to PEP8 and use 4 spaces for indentation in Python. We understand many of you will be distressed by this idea, but the good news is it’s really easy to configure pressing the tab key to input 4 spaces in your editor. In most cases, you’ll forget there was ever a problem!

Python also allows for hanging indents with variable amounts of characters, but we let Black handle the formatting for those for us.

Maximum Line Length

This is probably the place we differ from PEP8 the most. PEP8 recommends a 79 character limit, but in practice we find this to be too short - especially when following the 4 character indent rule. By contrast, the default style from Black allows an 88 character length maximum, and enforces it during auto-formatting. However, if Black can’t break up a line, it will leave it in place. flake8 by default enforces the PEP8 line length, but we recommend configuring it to 99. When using Black and flake8 in this way together, Black will almost always keep your line length below 88, but if it can’t break it up, flake8 won’t complain until you go over 99 characters.

Naming Conventions

Per PEP8’s naming conventions:

  • CapWords for classes and type names
  • snake_case for variables, functions, modules, and package names
  • SCREAMING_SNAKE_CASE for constants

Use variable names that describe what the data represents. Readability counts, so full words are generally preferable to shorthand (course is better than crs). Vowels are important!

Refrain from including the data type as part of the variable name. Doing so adds visual clutter and doesn’t improve understanding of the code. Instead of course_list or course_dict, use courses. Instead of course_str consider something like course_name or course_code. Use docstrings and comments to state what type a variable is, as necessary.

Single letter variable names (a, i, etc.) are sometimes acceptable, but should be used sparingly. If you find you’re using i as an iterator counter, there’s probably a more Pythonic way to do it!

Instead of using an index to loop through a list:

# Don't use this
while i < len(courses):
    print(courses[i])
    i += 1

# Nor this
for i in range(len(courses)):
    print(courses[i])

Loop over the list directly:

# Much better!
for course in courses:
    print(course)

If you really need the index, use enumerate:

# Better, with numbers!
for i, course in enumerate(courses):
    print(f"{i}: {course}")

Python doesn’t have “private” variables, but prefixing a variable with an underscore (e.g. _internal_use) indicates the variable is for internal use and it won’t be imported when using import * (which you shouldn’t be relying on anyways).

String Quotes

PEP8 does not specify a preference between single quotes (') and double quotes ("). Some people prefer single quotes because they are easier to type. Black prefers double quotes for readability. We recommend typing whatever you feel comfortable with, but allowing Black to update to double quotes before committing.

Exception: when a string contains double quotes characters (but no single quote characters), use single quotes instead of escaping the double quotes (i.e. 'They said "Hello"' is easier to read than "They said \"Hello\"")

Imports

The guidance from PEP8 on imports specifies that they should be on separate lines, but multiple imports from the same module/path may be on the same line. Imports must be at the top of the file, and should be grouped into three groups separated by a blank line in this order:

  1. Standard Library (built into Python, e.g. io, sys, logging)
  2. Third Party (e.g. requests, canvasapi, django)
  3. Local application (e.g. myapp, ucfhere, soulpatch)

Don’t want to remember these import rules? Never fear. Use isort and it will handle it for you! See the Isort section for more details.

Absolute imports are strongly preferred over relative imports.

Finally, avoid wildcard imports (i.e. from <module> import *) unless absolutely necessary. If you’re not sure, it’s not necessary.

Formatting and Linting Tools

We use three primary tools for linting and automatically formatting code:

  • black - formatter
  • flake8 - linter
  • isort - import sorter

Combining these tools creates a powerful enforcement mechanism for code quality and may even help you find bugs as you create them! Every project should include these tools as part of a CI/CD process to prevent noncompliant code from being merged into the core branches. Embedding them into a project’s processes means less time arguing over silly style and syntax quirks, and more time reviewing the design and architecture of code. If you find a Python project that is not enforcing code quality with these tools, you should add them! Future developers (yourself included) will thank you.

Git precommit hooks and editor/IDE-level packages are available for the individual contributor to prevent them from comitting noncompliant code.

Black - Formatter

Black is our preferred auto-formatter for Python. Any developer can have their code formatted however they want, so long as it’s Black.

When you run black, it will go through your project and automatically make formatting fixes for you. If you don’t want the automatic fixes, run it with the --check flag.

See the Python Tooling Task Guide for installation, configuration, and usage instructions.

Flake8 - Linter

flake8 is actually 3 tools combined:

  • pyflakes - error checker
  • pycodestyle (formerly known as pep8) - style checker (enforces PEP8 standard)
  • mccabe - complexity checker

Unlike black, running flake8 will not modify code; it will only tell you where and what the errors are. You will need to perform the fixes yourself.

See the Python Tooling Task Guide for installation, configuration, and usage instructions.

Isort - Import Sorter

isort is a tool that will sort all your imports according to the standard set forth by PEP8 (see Imports section above).

Running isort will automatically change the import order for you. To get a list of errors without making changes, run with the --check-only flag.

See the Python Tooling Task Guide for installation, configuration, and usage instructions.