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
, andisort
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? 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 namessnake_case
for variables, functions, modules, and package namesSCREAMING_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:
- Standard Library (built into Python, e.g.
io
,sys
,logging
) - Third Party (e.g.
requests
,canvasapi
,django
) - 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
- formatterflake8
- linterisort
- 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 checkerpycodestyle
(formerly known aspep8
) - 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.