Make your code consistent through style conventions. For interactive reading and executing code blocks and find b08-pystyle.ipynb, or install Python and JupyterLab locally.
Watch this section as a video
Watch this section as a video on the @Hydro-Morphodynamics channel on YouTube.
Take a deep breath, take off, and look at what you have learned so far from a new perspective. After this chapter, it will be worth having another look at your old code and formatting it robustly. The style guidelines presented here go beyond visual aesthetics and aid in writing effective code.

Background and PEP¶
This style guide highlights parts of the PEP 8 - Style Guide for Python Code by Guido van Rossum, Barry Warsaw, and Nick Coghlan. The full document is available at python.org and only aspects with relevance for the applications shown in this eBook are featured in this chapter.
What is a PEP? PEP stands for Python Enhancement Proposal. A PEP is a design document that provides information to the Python community or describes a proposed feature, process, or related change. There are many PEPs, including standards-track, informational, and process proposals. This chapter highlights recommendations from PEP 8, the style guide for Python code, by Guido van Rossum, Barry Warsaw, and Alyssa Coghlan.
Many IDEs, including PyCharm or VS Code, provide auto-completion and tooltips with PEP style guidance to aid consistent programming. Thus, when your IDE underlines anything in your script, check the reason for that and consider modifying the code accordingly.
The Zen of Python¶
Are we getting spiritual? Far from it. The Zen of Python is an informational PEP (20) by Tim Peters to guide programmers. It is a couple of lines summarizing good practice in coding. Python’s Easter Egg import this prints the Zen of Python in any Python interpreter:
import thisThe Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Code Layout¶
Maximum Line Length¶
PEP 8 recommends limiting code lines to 79 characters. Flowing text in comments and docstrings should be limited to 72 characters. A team may agree on a code-line limit of up to 99 characters, provided that comments and docstrings remain limited to 72 characters.
Indentation¶
Indentation groups statements into suites controlled by constructs such as for, if, while, try, with, def, and class. PEP 8 recommends four spaces per indentation level. Indentation does not by itself create a new variable scope: names assigned in an if or for suite remain in the surrounding scope. Functions, classes, modules, and some comprehensions have their own scoping rules.
for i in range(1, 2):
print("I'm one level indented.")
if i == 1:
print("I'm two levels indented.")I'm one level indented.
I'm two levels indented.
Because long lines of code are bad practice, we sometimes need to use line breaks when assigning for example a list or calling a function. In these cases, the next, continuing line is also indented and there are different options to indent multi-line assignments. Here, we want to use the style code of using an opening delimiter for indentation:
a_too_long_word_list = ["Do", "not", "hard-code", "something", "like", "this.",
"There", "are", "better", "ways."]
a_better_indented_list = [
"Do",
"not",
"hard-code",
"something",
"like",
"this.",
"...",
]Recall: PyCharm, VS Code, and many other IDEs automatically layout indentation.
Line Breaks of Expressions with Binary Operators¶
When binary operators are part of an expression that exceeds the maximum line length of 79 characters, the line break should be before the binary operators.
import pandas as pd
dummy_df = pd.get_dummies(
pd.Series(["variable1", "parameter2", "sensor3"]),
dtype=int,
)
print(dummy_df.head(3))
dum_sum = (
dummy_df["variable1"]
+ dummy_df["parameter2"]
- dummy_df["sensor3"]
)
parameter2 sensor3 variable1
0 0 0 1
1 1 0 0
2 0 1 0
Blank Lines¶
To separate code blocks, hitting the Enter key many times is a very inviting option. However, the random and mood-driven use of blank lines results in unstructured code. This is why PEP 8 authors provide guidance also on the use of blank lines:
Surround class definitions and top-level functions (i.e., functions where the
def-line is not indented) with two blank lines.Surround methods (e.g., functions within a class) with one blank line.
Use blank lines sparsely in all other code to indicate logical sections.
# blank 1 before top-level function
# blank 2 before top-level function
def top_level_function():
pass
# blank 1 after top-level function
# blank 2 after top-level functionBlanks (Whitespaces)¶
Avoid unnecessary whitespace immediately inside parentheses, brackets, or braces; before commas, semicolons, and ordinary colons; or between a function name and its argument list. Write function(e1, e2), (1,), a_dict = {a_key: a_value}, and def fun(arg=0.0):.
Use spaces around assignment, comparison, and Boolean operators. For arithmetic expressions, add spaces around the lowest-precedence operators and use judgment to make precedence clear; for instance, hypot2 = x*x + y*y.
Packages and Modules¶
Imports¶
Imports normally appear after the module docstring and before module globals. Group them in this order, with a blank line between groups: standard library, related third-party packages, and local application or library imports. Put ordinary imports on separate lines and avoid wildcard imports. Every import should have its own line and avoid using the comma sign for multiple imports:
import os
import sys
import numpy as np
from my_package import my_moduleNaming Packages and Script¶
New, custom packages or modules should have short and all-lowercase names, where underscores may be used to improve readability (discouraged for packages).
Comments¶
Block and Inline Comments¶
Block comments are indented to the same level as the code they describe, and each line begins with # . Use inline comments sparingly. An inline comment appears on the same line as a statement, is separated from it by at least two spaces, and begins with # .
Docstrings¶
A docstring is a string literal that occurs as the first statement in a module, function, class, or method. It becomes available through the object’s __doc__ attribute. PEP 257 recommends triple double quotes. For example:
a_list = [1, 2]
print(a_list.__doc__)Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
When writing a Python function, docstrings are introduced immediately after the def ... line with triple double-quotes:
def let_there_be_light(*args, **kwargs):
"""Print a sunrise message and return `True`.
Args:
*args: Positional arguments accepted but not used.
**kwargs: Keyword arguments accepted but not used.
Returns:
`True` in all cases.
"""
print("Sunrise")
return True
print(let_there_be_light.__doc__)
Bright function accepting any input argument with indifferent behavior.
:param an_input_argument: STR or anything else
:param another_input_argument: FLOAT or anything else
:return: True (in all cases)
Note that the recommendations on docstrings are provided with PEP 257 rather than PEP 8.
Name Conventions¶
Definition of Name Styles¶
The naming conventions use the following styles (source: python.org):
Classes normally use CapWords, for example
MyClass.User-defined exception classes follow the class-naming convention and normally use the suffix
Errorwhen they represent an error, for exampleConfigurationError.Functions, methods, and variables use lowercase words separated by underscores as needed for readability.
Constants normally use uppercase words separated by underscores, for example
WATER_DENSITY = 1000.
Some variable name formats trigger a particular behavior of Python:
_single_leading_underscorevariables indicate weak internal use and will not be imported withfrom module import *__double_leading_underscorevariables invoke name mangling in classes (e.g., a method called__dluof the classMyClasswill be mangled into_MyClass__dlu)__double_leading_and_trailing_underscore__variables are magic objects or attributes in user-controlled namespaces (e.g.,__init__or__call__in classes)
Only use documented magic attributes and never invent them. Read more about magic methods in the chapter on Python classes.single_trailing_underscore_variables are used to avoid conflicts with Python keywords (e.g.,MyClass(class_='AnotherClass'))
Object Names¶
Use the above-defined styles for naming Python items as follows:
Classes:
CamelCase(CapWords) letters only such asMyClassConstants:
UPPERCASEletters only, where underscores may improve readability (e.g., use at a module level for example to assign water densityRHO = 1000)Exceptions:
CamelCase(CapWords) letters only (exceptions should be predefined Error classes; typically use the suffixError(e.g.,TypeError)Functions:
lowercaseletters only, where underscores may improve readability; sometimesmixedCaseapplies to ensure backward compatibility of prevailing stylesMethods (class function, non-public):
_lowercaseletters only with a leading underscore, where underscores may improve readabilityMethods (class function, public):
lowercaseletters only, where underscores may improve readabilityModules:
lowercaseletters only, where underscores may improve readabilityPackages:
lowercaseletters only, where underscores are discouragedVariables:
lowercaseletters only, where underscores may improve readabilityVariables (global):
lowercaseletters only, where underscores may improve readability; note that “global” should limit to variable usage within one module only.
More Code Style Recommendations¶
To ensure code compatibility and program efficiency, the PEP 8 style guide provides other general recommendations (read more in the Python docs):
Prefer a
defstatement when creating a named function; do not assign a lambda expression directly to a name. A short lambda can be appropriate when passed directly as an argument, for exampleitems.sort(key=lambda item: item.name).When exceptions are expected, use
try-exceptclauses (see the errors and exceptions section).Ensure that methods and functions return objects consistently, for example:
import numpy as np
def a_function_with_return(x):
if x > 0:
return np.sqrt(x)
return np.nan