Good Coding
Practices
Daniel Perrefort – University of Pittsburgh
Best practices are any procedure that is
accepted as being the most effective either
by consensus or by prescription.
What is a Best Practices can range from stylistic to in-depth
Practice? design methodologies.
"A universal convention supplies all of maintainability, clarity, consistency, and a
foundation for good programming habits too."
—Tim Peters on comp.lang.python, 2001-06-16
PEP’s and good styling
A Roadmap Writing good documentation
How to organize your project
Python Enhancement Protocol (PEP)
“A PEP is a design document providing information to the Python community, or
describing a new feature for Python or its processes or environment.” (PEP 1)
Important PEP 8: Style Guide for Python Code
Fundamentals
PEP 20: The Zen of Python
PEP 257: Docstring Conventions
Bonus PEPs PEP 484: Type Hints
PEP 498: Literal String Interpolation
PEP 572: Assignment Expressions
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.
PEP 20: The Readability counts.
Special cases aren't special enough to break the rules.
Zen of Python Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
>>> import this 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 is read much more often than it is
written.
PEP 8: Style Easy to read means easier to develop.
Guide for
Well written code conveys
Python Code professionalism.
Code is a deliverable part of your
project!
PEP8: Code Layout
Your probably already familiar with…
Using 4 spaces per indentation level (not tabs!)
Putting two blank lines before functions and classes
Limiting line lengths to:
79 characters for code
72 characters for long blocks of text
It is okay to increase the line length limit up to 99 characters
PEP8: Code Layout
# !/usr/bin/env python3.7
# -*- coding: UTF-8 -*-
"""This is a description of the module."""
import json
import os
from astropy.table import Table, vstack
from my_code import utils
__version__ = 0.1
def my_function():
...
PEP 8: Naming Conventions
TYPE NAM ING CO NVENT IO N EX AM P L ES
Function Use lowercase words separated by underscores. function, my_function
Variable Use lowercase letters or word, or words separated with x, var, my_variable
underscores. (I.e., snake_case)
Class Start each word with a capital letter. Do not separate words with Model, MyClass
underscores. (I.e., CamalCase)
Method Use lowercase words separated with underscores. class_method, method
Constant Use an uppercase single letter, word, or words separated by CONSTANT, MY_CONSTANT
underscores.
Module Use short lowercase words separated with underscores. module.py, my_module.py
Package Use short lowercase words without underscores. package, mypackage
PEP8: General Recommendations
Use `is` when comparing singletons
Use `is not` instead of `not ... is`
# Wrong # Correct
if foo == None: if foo is not None:
do_something() do_something()
# Also wrong
if not foo is None:
do_something()
PEP8: General Recommendations
Always use a `def` statement instead of an assignment statement for
anonymous (lambda) expressions
# Wrong # Correct
f = lambda x: 2 * x def double(x):
return 2 * x
PEP8: General Recommendations
Derive exceptions from `Exception` rather than `BaseException`
Use explicit exception catching (avoid bare exceptions)
Keep `try` statements as simple as possible
# Wrong # Correct
try: try:
import platform_specific_module import platform_specific_module
my_function()
except ImportError:
except: platform_specific_module = None
platform_specific_module = None
else:
my_function()
PEP8: General Recommendations
Booleans are already Booleans – they don’t need comparisons
For sequences, (e.g., a lists), use the fact that empty sequences are false
# Wrong: # Correct for sequences and booleans
if my_boolean == True: if some_variable:
do_something() do_something()
# Worse:
if my_boolean is True:
do_something()
# Still bad:
if len(my_list) != 0:
do_something()
If You Take Away One Thing...
PEP8 inspection is built into many Integrated Development
Environments (IDEs)
PyCharm: https://www.jetbrains.com/pycharm/
Atom-pep8: https://atom.io/packages/pep8
Command line tools for PEP 8 are also available Side Note
Pylint: http://pylint.pycqa.org/
Flake8: https://flake8.pycqa.org/
Jupyter Plugins:
Python Black: https://github.com/drillan/jupyter-black
Documentation is key to reusable code
PEP 257: Never assume you will remember what
your code does (or how it works)
Docstring
Documentation can include technical
Conventions notes and derivations.
Saves you headaches when you revisit a
project in part or in whole
Good Documentation Should…
Explain what each function / module / package does or is responsible for
Be understandable to you when you revisit the code in 6 months
Be understandable by someone new to the project (but not necessarily new to
the subject matter)
Be specific and to the point
PEP257: Single Line Docs
Triple quotes are always used
The closing quotes are on the same line as the opening quotes.
The docstring is a phrase ending in a period. It prescribes the function’s
effect as a command ("Do this", "Return that"), not as a description; e.g. don't
write "Returns the pathname .
def kos_root():
"""Return the pathname of the KOS root directory."""
...
PEP257: Multi-Line Docs
Start with a single line docstring
Include additional documentation as necessary
Always document arguments and returns
def complex(real=0.0, imag=0.0):
"""Form a complex number.
Here is where you would put some additional, in-depth documentation.
Keyword arguments:
real -- the real part (default 0.0)
imag -- the imaginary part (default 0.0)
Returns:
An imaginary number corresponding to the given arguments
"""
External Style Guides (Google)
Based on the principle that docs in the code should be human readable
def connect_to_next_port(minimum):
"""Connects to the next available port.
Args:
minimum: A port value greater or equal to 1024.
Returns:
The new minimum port.
Raises:
ConnectionError: If no available port is found.
"""
http://google.github.io/styleguide/pyguide.html
Document the Code AND the Project
Extensive project documentation isn’t always necessary and should scale to
meet your project requirements.
Include a README file at minimum
Describe the project goals and general approach
Does not need to be super in depth
For larger projects, you might document:
Design choices or style guides
Project notes (e.g. from papers you read)
A development plan / roadmap
Use tools like Sphinx and Read The Docs to
generate automatic documentation
Sphinx: https://www.sphinx-doc.org/
RTD: https://readthedocs.org
Running the setup script: Side Note
$ pip install sphinx
$ sphinx-quickstart
PEP 484: Type Hints
“New” as of Python 3.5 Type hints are probably not a
Not extensively used but can be extremely helpful for “best practice” but planning out
your code ahead of time (e.g.
Adding inspection support when developing API’s function signatures) is!
Enforcing type linting in your own projects
from typing import Union
PathLike = Union[str, Path]
def greeting(name: str) -> str:
return 'Hello ' + name
def process_directory(path: PathLike):
return 'Hello ' + name
Proper organization promotes
reproducibility
How to How you set up your project effects your
ability to collaborate
Organize
Version control provides continuity and
Your Project collaboration
Virtual environments eliminate
dependency conflicts
Source Code Organization: Directories
D IR ECTO RY US AG E
source Your project source code. The code responsible for performing your analysis.
scripts Individual scripts responsible for running separate stages of your analysis.
plotting Scripts for creating finalized plots.
docs Stores your project’s documentation.
notebooks For holding notebooks used in exploratory analysis.
tests Your project test suite.
examples Use if you want to demonstrate your project.
F IL E US AG E
README.md Provides a project description.
requirements.txt Outlines your project dependencies.
LICENSE.txt License for the distribution of your code (or the forked source). (GNU)
The Infamous “Scripts” Directory
Scripts should NOT be where your analysis logic is
Scripts should NOT be a dumping ground for scratch code
Each script should represent a single distinct task. For e.g.,
Run image calibration
Fit object light-curves
Download / format data from a remote server
Include (short) module level docs for each script
Use Version Control
Allows easier collaboration, especially with large teams.
Provides descriptions of each change and why it was made.
Backs up your project incase something goes wrong.
You can revert changes or recover previous code.
Git Cheat Sheet
GIT BASICS REWRITING GIT HISTORY
Put one of these at
gi t i ni t Creat e empt y Git repo in specified direct ory. Run w it h no
argument s t o init ialize t he current direct ory as a git reposit ory.
gi t commi t Replace t he last commit w it h t he staged changes and last commit
combined. Use w it h not hing st aged t o edit t he last commit ’s message.
your desk! (atlassian)
<di r ect or y> - - amend
Clone repo located at <r epo> onto local machine. Original repo can be Rebase t he current branch ont o <base> . <base> can be a commit ID,
gi t cl one <r epo> gi t r ebase <base>
located on t he local filesystem or on a remote machine via HTTP or SSH. branch name, a t ag, or a relat ive reference t o HEAD.
gi t conf i g Define aut hor name t o be used for all commit s in current repo. Devs Show a log of changes t o t he local reposit ory’s HEAD.
gi t r ef l og
user . name <name> commonly use - - gl obal flag t o set config opt ions f or current user. Add - - r el at i ve- dat e flag t o show dat e info or - - al l t o show all refs.
gi t add St age all changes in <di r ect or y> for t he next commit .
<di r ect or y> Replace <di r ect or y> w it h a <f i l e> t o change a specific fil e. GIT BRANCHES
gi t commi t - m Commit t he st aged snapshot , but inst ead of launching List all of t he branches in your repo. Add a <br anch> argument t o
gi t br anch
" <message>" a t ext edit or, use <message> as t he commit message. creat e a new branch w it h t he name <br anch> .
gi t checkout - b Creat e and check out a new br anch named <br anch> .
gi t st at us List w hich fil es are st aged, unst aged, and unt racked.
<br anch> Drop t he - b flag t o checkout an exist ing branch.
Display t he ent ire commit hist ory using t he def ault format .
gi t l og gi t mer ge <br anch> Merge <br anch> int o t he current branch.
For cust omizat ion see addit ional opt ions.
Show unst aged changes bet w een your index and
gi t di f f REM OTE REPOSITORIES
w orking direct ory.
gi t r emot e add Creat e a new connect ion t o a remot e repo. Aft er adding a remot e,
UNDOING CHANGES <name> <ur l > you can use <name> as a short cut for <ur l > in ot her commands.
gi t r ever t Creat e new commit t hat undoes all of t he changes made in gi t f et ch Fet ches a specific <br anch> , from t he repo. Leave off <br anch>
<commi t > <commi t > , t hen apply it t o t he current branch. <r emot e> <br anch> t o fet ch all remot e refs.
Remove <f i l e> from t he staging area, but leave t he w orking directory Fet ch t he specified remot e’s copy of current branch and
gi t r eset <f i l e> gi t pul l <r emot e>
unchanged. This unst ages a file w it hout overw rit ing any changes. immediat ely merge it int o t he local copy.
Show s w hich fil es w ould be removed from w orking direct ory. gi t push Push t he branch t o <r emot e> , along w it h necessary commit s and
gi t cl ean - n
Use t he - f flag in place of t he - n flag t o execut e t he clean. <r emot e> <br anch> object s. Creat es named branch in t he remot e repo if it doesn’t exist .
Visit at lassian.com /git for m ore inform at ion, t raining, and t ut orials
Virtual Environments
Use a different environment for each project
Prevents dependency conflicts and encapsulates projects separately.
Environments can be shared!
$ conda create –n my_environment python=3.8
$ conda activate my_environment
$ ...
$ conda deactivate
Conclusions
Focus on clean, organized code
Easier to develop and collaborate on
Conveys professionalism
Always include documentation for your code
Scale to project needs
Keep your projects organized for reproducibility