Skip to content

Instantly share code, notes, and snippets.

@bourque
Created January 6, 2018 00:57
Show Gist options
  • Save bourque/5004594018c9bf16a821410f5c9327a7 to your computer and use it in GitHub Desktop.
Save bourque/5004594018c9bf16a821410f5c9327a7 to your computer and use it in GitHub Desktop.
A condensed version of PEP8 and PEP257 in notebook form
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook aims to condense and illustrate the examples given in the [`PEP 8` Style Guide for Python](https://www.python.org/dev/peps/pep-0008/) and the [`PEP 257` Docstring Conventions](https://www.python.org/dev/peps/pep-0257/) in notebook form. The text and examples in this notebook are mostly taken straight from the `PEP 8` and `PEP 257` documents, but some areas are modified to provide clearer examples."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# `PEP 8` Style Guide Examples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A Foolish Consistency is the Hobgoblin of Litte Minds"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Code is read much more often than it is written\n",
"- Goal is to improve the readbility of code and make it consistent across the wide spectrum of Python code\n",
"- \"Readability counts\"\n",
"- A style guide is about consistency\n",
"- Consistency within a project is more important\n",
"- Consistency within a module or function is most important\n",
"- Know when to be inconsistent - Style guide reccomendations are not always applicable"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code Layout"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Indentation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Use 4 spaces per indentation level\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"# Aligned with opening delimiter.\n",
"foo = long_function_name(var_one, var_two,\n",
" var_three, var_four)\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"# More indentation included to distinguish this from the rest.\n",
"def long_function_name(\n",
" var_one, var_two, var_three,\n",
" var_four):\n",
" print(var_one)\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"# Hanging indents should add a level.\n",
"foo = long_function_name(\n",
" var_one, var_two,\n",
" var_three, var_four)\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"# The closing brace/bracket/paranethesis on multiline constructs may\n",
"# line up under the first non-whitespace character\n",
"my_list = [\n",
" 1, 2, 3,\n",
" 4, 5, 6,\n",
" ]\n",
"result = some_function_that_takes_arguments(\n",
" 'a', 'b', 'c',\n",
" 'd', 'e', 'f',\n",
" )\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"# The closing brace/bracket/paranethesis on multiline constructs may\n",
"# line up under the line that starts the mutliline construct\n",
"my_list = [\n",
" 1, 2, 3,\n",
" 4, 5, 6,\n",
"]\n",
"result = some_function_that_takes_arguments(\n",
" 'a', 'b', 'c',\n",
" 'd', 'e', 'f',\n",
")\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"# Arguments on first line forbidden when not using vertical alignment.\n",
"foo = long_function_name(var_one, var_two,\n",
" var_three, var_four)\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"# Further indentation required as indentation is not distinguishable.\n",
"def long_function_name(\n",
" var_one, var_two, var_three,\n",
" var_four):\n",
" print(var_one)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tabs or Spaces?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Spaces are the preferred indentation method\n",
"- Python 3 disallows mixing use of tabs and spaces\n",
"- Many modern text editors can convert tabs to spaces for you"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Maximum Line Length"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- All lines of code should be limited to 79 characters, unless it reduces the readability of the code"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Should a line break before or after a binary operator?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"# Operators sit far away from their operands\n",
"income = (gross_wages +\n",
" taxable_interest +\n",
" (dividends - qualified_dividends) -\n",
" ira_deduction -\n",
" student_loan_interest)\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"# Easy to match operators with operands\n",
"income = (gross_wages\n",
" + taxable_interest\n",
" + (dividends - qualified_dividends)\n",
" - ira_deduction\n",
" - student_loan_interest)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Blank Lines"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Surround top-level function and class definitions with two blank lines:\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"def my_first_function():\n",
" pass\n",
" \n",
"\n",
"def my_second_function():\n",
" pass\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"def my_first_function():\n",
" pass\n",
" \n",
"def my_second_function():\n",
" pass\n",
"```\n",
"\n",
"- Method definitions inside of a class are surrounded by a single blank line:\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"class MyClass():\n",
"\n",
" def my_first_method():\n",
" pass\n",
" \n",
" def my_second_method():\n",
" pass\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"class MyClass():\n",
"\n",
" def my_first_method():\n",
" pass\n",
" \n",
" \n",
" def my_second_method():\n",
" pass\n",
"```\n",
"\n",
"- Extra blank lines may be used sparingly to sepeare groups of related functions/methods\n",
"- Blank lines may be ommitted between a group of related one-liners\n",
"- Use blank lines within functions and methods, sparingly, to indicate logical sections:\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"def get_coordinates():\n",
" \"\"\"Read in the data file and return a list of the x and y coordinates\"\"\"\n",
" \n",
" # Read in the file\n",
" with open('my_file.txt', 'r') as f:\n",
" data = f.readlines()\n",
" \n",
" # Get the first two columns, which are the x and y coordinates\n",
" x_coords = [item.strip().split(',')[0] for item in data]\n",
" y_coords = [item.strip().split(',')[1] for item in data]\n",
" \n",
" return x_coords, y_coords\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"def get_coordinates():\n",
" \"\"\"Read in the data file and return a list of the x and y coordinates\"\"\"\n",
" # Read in the file\n",
" with open('my_file.txt', 'r') as f:\n",
" data = f.readlines()\n",
" # Get the first two columns, which are the x and y coordinates\n",
" x_coords = [item.strip().split(',')[0] for item in data]\n",
" y_coords = [item.strip().split(',')[1] for item in data]\n",
" return x_coords, y_coords\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Imports"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Imports should be on separate lines, except from importing multiple modules from one library:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"import os\n",
"import sys\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"from subprocess import Popen, PIPE\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"import sys, os\n",
"```\n",
"\n",
"- Imports are always put at the top of the file, after module comments and docstring, but before module globals and function/class definitions:\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"\"\"\"This is an example module.\n",
"\n",
"Authors\n",
"-------\n",
" Francesca Boffi\n",
"\n",
"Use\n",
"---\n",
" >>> python example.py\n",
"\"\"\"\n",
"\n",
"import os\n",
"import sys\n",
"\n",
"\n",
"def my_function():\n",
" pass\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"import os\n",
"import sys\n",
"\n",
"\"\"\"This is an example module.\n",
"\n",
"Authors\n",
"-------\n",
" Francesca Boffi\n",
"\n",
"Use\n",
"---\n",
" >>> python example.py\n",
"\"\"\"\n",
"\n",
"def my_function():\n",
" pass\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"\"\"\"This is an example module.\n",
"\n",
"Authors\n",
"-------\n",
" Francesca Boffi\n",
"\n",
"Use\n",
"---\n",
" >>> python example.py\n",
"\"\"\"\n",
"\n",
"def my_function():\n",
" pass\n",
" \n",
"import os\n",
"import sys\n",
"```\n",
"\n",
"- Imports should be grouped in the following order:\n",
" 1. Standard library imports\n",
" 2. Third pary imports\n",
" 3. local application/library specific imports\n",
"- For each group, imports should be placed in alphabetical order\n",
" \n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"import os\n",
"import sys\n",
"\n",
"from astropy.io import fits\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"from my_module import my_function\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"# Imports not in alphabetical order\n",
"import sys\n",
"import os\n",
"\n",
"from astropy.io import fits\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from my_module import my_function\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"# Imports not in groups\n",
"from astropy.io import fits\n",
"from my_module import my_function\n",
"import numpy as np\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"import sys\n",
"```\n",
"\n",
"- Always use explicit imports\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"from astropy import ascii, io, time\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"from astropy import *\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## String Quotes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Use of single or double quotes for strings is permitted\n",
"- Stay consisitent with single or double quotes within a module"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Whitespace in Expressions and Statements"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"- Avoid whitespaces immediately inside parathensis, brackets, or braces\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"spam(ham[1], {eggs: 2})\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"spam( ham[ 1 ], { eggs: 2 } )\n",
"```\n",
"\n",
"- Avoid whitespaces immediately before a comma, semicolon, or colon\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"if x == 4: print x, y; x, y = y, x\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"if x == 4 : print x , y ; x , y = y , x\n",
"```\n",
"\n",
"- Avoid whitespaces immediately before the open paraenthesis that starts the argument list of a function call\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"spam(1)\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"spam (1)\n",
"```\n",
"\n",
"- Avoid whitespaces immediately before the open bracket that starts an indexing or slicing\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"dct['key'] = lst[index]\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"dct ['key'] = lst [index]\n",
"```\n",
"\n",
"- Avoid more than one whitespace around an assignment operator in order to align it with another\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"x = 1\n",
"y = 2\n",
"long_variable = 3\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"x = 1\n",
"y = 2\n",
"long_variable = 3\n",
"```\n",
"\n",
"- Avoid trailing whitespaces anywhere. Some editors have features to automatically remove these.\n",
"- Always surround the following binary operators with a single space on either side: `=`, `+=`, `-=`, `==`, `<`, `<=`, `>`, `>=`, `in`, `not`, `is`, `and`, `or`\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"i = i + 1\n",
"submitted += 1\n",
"x = x*2 - 1\n",
"hypot2 = x*x + y*y\n",
"c = (a+b) * (a-b)\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"i=i+1\n",
"submitted +=1\n",
"x = x * 2 - 1\n",
"hypot2 = x * x + y * y\n",
"c = (a + b) * (a - b)\n",
"```\n",
"\n",
"- Don't use spaces around the `=` sign when used to indicate a keyword argument\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"def complex(real, imag=0.0):\n",
" return magic(r=real, i=imag)\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"def complex(real, imag = 0.0):\n",
" return magic(r = real, i = imag)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Comments"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"- Comments that contradict the code are worse than no comments at all\n",
"- Make it a priority to keep comments up to date when the code changes\n",
"- Comments should be complete sentences, the first word should be capitalized\n",
"- Use two spaces after a sentence-ending period in multi-sentence comments\n",
"- Each comment should start with a `#` and a single space.\n",
"- Inline comments should be separeted by at least two spaces from the end of the statement\n",
"- Inline comments are unnecessary and distracting if they state the obvious\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"x = x + 1 # Increment x\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"x = x + 1 # Compensate for border\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Naming Conventions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Module names should follow the `lowercase_with_underscores` convention (e.g. `my_module.py`)\n",
"- Function and method names should follow the `lowercase_with_underscores` convention (e.g. `my_funciton()`)\n",
"- Class names should follow the `CamelCase` convention (e.g. `MyClass()`)\n",
"- Global variables should follow the `UPPERCASE_WITH_UNDERSCORES` convetion (e.g. `MY_GLOBAL_VAR`)\n",
"- Variable names should follow the `lowercase_with_underscores` convetnion (e.g. `my_normal_var`)\n",
"- Limit use of single character variable names to indicies and file handlers.\n",
"- Use of descriptive variable names is highly encouraged, even if it results in a long variable name\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"for i, name in enumerate(names):\n",
" print(i, name)\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"with open('filename.txt', 'r') as f:\n",
" data = f.readlines()\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"data = np.zeros((10,10))\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"data = np.zeros((10,10))\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"shutter_a = 'foo'\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"d = np.zeros((10,10))\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"dat = np.zeros((10,10))\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"shutr_a = 'foo'\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Programming Reccomendations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Comparison with `None` should always be done is `is` or `is not`, not with equality operators\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"if foo is None:\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"if foo is not None:\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"if not foo is None:\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"if foo != None:\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"if foo == None:\n",
"```\n",
"\n",
"- When catching exceptions, mention specific exceptions whenever possible instead of using a bare `except:` clause or catching a general `Exception`.\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"try:\n",
" import platform_specific_module\n",
"except ImportError:\n",
" platform_specific_module = None\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"try:\n",
" import platform_specific_module\n",
"except Exception:\n",
" platform_specific_module = None\n",
"```\n",
"\n",
"- Limit `try` clauses to the absolute minimum amount of code necessary to avoid masking bugs\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"try:\n",
" value = collection[key]\n",
"except KeyError:\n",
" return key_not_found(key)\n",
"else:\n",
" return handle_value(value)\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"try:\n",
" # Too broad!\n",
" return handle_value(collection[key])\n",
"except KeyError:\n",
" # Will also catch KeyError raised by handle_value()\n",
" return key_not_found(key)\n",
"```\n",
"\n",
"- Dont compare boolean values to `True` or `False` using `==`\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"if greeting:\n",
"```\n",
"\n",
"<b><font color='green'>Yes:</font></b>\n",
"```python\n",
"if greeting is False:\n",
"```\n",
"\n",
"<b><font color='red'>No:</font></b>\n",
"```python\n",
"if greeting == True:\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# `PEP 257` Dostring Convention Examples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- A docstring is a string literal that occurs as the first statement in a module, function, class, or method definition\n",
"- All modules, classes, functions, and methods should have docstrings\n",
"- Always use `\"\"\"`triple double quotes`\"\"\"` around docstrings\n",
"- There is no blank line before the docstring\n",
"- The docstring is a phrase ending in a period. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Some examples"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"#### Module docstring:\n",
"\n",
"```Python\n",
"\"\"\"Performs ingestion of HST/ACS data into the ``acsql`` database and\n",
"filesystem.\n",
"\n",
"This script is a wapper around ``acsql.ingest.ingest.py`` to ingest\n",
"multiple rootnames into the system. The user may supply a list of\n",
"individual rootnames to ingest, or (by default) ingest whichever\n",
"rootnames exist in the MAST cache but yet to exist in the ``acsql``\n",
"database.\n",
"\n",
"See ``acsql.ingest.ingest.py`` module docstrings for further\n",
"information on the ingestion process.\n",
"\n",
"Authors\n",
"-------\n",
" Matthew Bourque\n",
" \n",
"Use\n",
"---\n",
" This script is inteneded to be executed from the command line as\n",
" such:\n",
" \n",
" python ingest_production.py [-i|--ingest_filelist]\n",
" ['-f|--filetype']\n",
" \n",
" Parameters:\n",
" \n",
" (Optional) [-i|--ingest_filelist] - A text file containing\n",
" individual rootnames to be ingested. If not supplied, this\n",
" module will determine which rootnames are to be ingested by\n",
" comparing the MAST cache against what already exists in the\n",
" ``acsql`` database.\n",
" \n",
" (Optional) [-f|--filetype] - The type of file to ingest. May be\n",
" an indivual filetype (e.g. ``flt``) or ``all`` to ingest all\n",
" filetypes. ``all`` is the default value.\n",
"\"\"\"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python [conda env:astroconda3]",
"language": "python",
"name": "conda-env-astroconda3-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment