Python Style Guide

In [1]:
import addutils.toc ; addutils.toc.js(ipy_notebook=True)
Out[1]:

You will soon realize that the Python community often cite the Pythonic approach to do things.

'Pythonic' refers to the principles laid out in 'The Zen of Python': a collection of basic coding rules to allow Python code to be more readable, maintainable and accessible to both novice and experienced developers. You can access 'The Zen of Python' by typing at any time import this in any Python interpreter.

In [2]:
from addutils import css_notebook
css_notebook()
Out[2]:
In [3]:
import this
The 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!

1 PEP8

PEP is an acronym for Python Enhancement Proposals. The whole list can be found HERE.

PEP8 in particular contains coding convections and is perhaps the most explicit example of idioms within the Python community. In Computer Science, idioms are preferred ways of writing code (often there are many possible coding solutions to reach the same results, and some solutions are considered better than others, both for readability and performance reasons). We highly recommend to read PEP8 before start your career as a Python Programmer. It will be higly recommendable to use a PEP8 style-checking plugin to be shure your code is fully compliant with that rules.

2 Syntax and Naming Conventions

2.1 Avoid using semicolons at the end of lines

Even if allowed, python doesn't need it!

In [4]:
# WRONG
var = 15;
s = "I like semicolons";
a = 1; b =2; c = 3
In [5]:
# CORRECT
var = 15
s = "No semicolons!"
a, b, c = 1, 2, 3

2.2 Avoid having multiple statements on a single line

In [6]:
condition = True
# WRONG
if condition: a = 1; b =2; c = 3

# CORRECT
if condition:
    a, b, c = 1, 2, 3

2.3 Indent your code block with 4 spaces

Never use tabs or mix tabs and spaces. In cases of implied line continuation, you should align wrapped elements either vertically, as for the examples in the line length section; or using a hanging indent of 4 spaces, in which case there should be no argument on the first line.

# WRONG - Stuff on first line forbidden lfunc = long_function_name(var_one, var_two, var_three, var_four) # CORRECT - Aligned with opening delimiter lfunc = long_function_name(var_one, var_two, var_three, var_four)

2.4 Imports: Should always be on separate lines, if refered to different modules.

Always on top of modules. Avoid from module import * if not strictly required.
Imports should be grouped in the following order:

  • standard library imports
  • related third party imports
  • local application/library specific imports
In [7]:
# WRONG 
import sys, os
from math import *
In [8]:
# CORRECT
import sys
import os
from math import gamma

2.5 Whitespace: required or not?

No spaces in parentheses, no whitespace before a comma, semicolon, or colon. Do use whitespace after a comma, semicolon, or colon except at the end of the line.

# WRONG spam( ham[ 1 ], { eggs: 2 }, [ ] ) #CORRECT spam(ham[1], {eggs: 2}, [])

No whitespace before the open paren/bracket that starts an argument list, indexing or slicing.

# WRONG spam (1) dict ['key'] = list [index] # CORRECT spam(1) dict['key'] = list[index]

Don't use spaces around the = operator when used to indicate a keyword argument or a default parameter value.

In [9]:
# WRONG
def complex(real, imag = 0.0):
    return magic(r = real, i = imag)
In [10]:
# CORRECT
def complex(real, imag=0.0):
    return magic(r=real, i=imag)

Surround binary operators with a single space on either side for assignment (=), comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), and Booleans (and, or, not). Use your better judgment for the insertion of spaces around arithmetic operators but always be consistent about whitespace on either side of a binary operator.

# WRONG
        x<1


        # CORRECT
        x == 1

Don't use spaces to vertically align tokens on consecutive lines, since it becomes a maintenance burden (applies to :, #, =, etc.):

In [11]:
# WRONG
short     = 1000  # comment
long_name = 2     # comment that should not be aligned

dictionary = {
   'foo'      : 1,
   'long_name': 2,
}
In [12]:
# CORRECT
short = 1000  # comment
long_name = 2  # comment that should not be aligned

dictionary = {
    'foo': 1,
    'long_name': 2,
}

2.6 Naming: names in python should be chosen according to the following conventions:

  • object naming:
    module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_CONSTANT_NAME, global_var_name, instance_var_name, function_parameter_name, local_var_name.
  • avoid single character names except for counters or iterators
  • avoid dashes (-) in any package/module name
  • __double_leading_and_trailing_underscore names (reserved by Python)

3 Working with Data

3.1 Avoid using a temporary variable when swapping two variables

There is no reason to swap using a temporary variable in Python. We can use tuples to make our code more readable

In [13]:
# WRONG - Swap two variables using a temporary variable
a, b = 10, 20
temp = a
a = b
b = temp
In [14]:
# CORRECT - Swap two variables using tuples
(a,b) = (b,a) # Parentesis can be omitted

3.2 Use tuples to unpack data

In Python, it is possible to 'pack' and 'unpack' data. This is mostly used while passing multiple values to functions.

In [15]:
# WRONG - Unpack values with single instructions
packed = ['car', 'Cevy', 160] 
vehicle = packed[0]
make = packed[1]
speed = packed[2]
In [16]:
# CORRECT - Unpack values using tuples
packed = ['car', 'Cevy', 160] 
(vehicle, make, speed) = packed

3.3 Strings: Use join and list to create a string from a list and viceversa

In [17]:
mylist = ['u', 's', 'e', ' ', 'j', 'o', 'i', 'n', '(', '', ')']
# WRONG
mystr = ''
for letter in mylist:
    mystr = mystr + letter
    
# CORRECT
mystr = ''.join(mylist)

# CORRECT: generate a list from a string
mylist2 = list('this will be a list')
print(mylist2)
['t', 'h', 'i', 's', ' ', 'w', 'i', 'l', 'l', ' ', 'b', 'e', ' ', 'a', ' ', 'l', 'i', 's', 't']

3.4 Strings: Use startswith and endswith instead of string slicing to check for prefixes or suffixes.

In [18]:
mystr = 'Check me'
# WRONG
print(mystr[:5] == 'Check')

# CORRECT
print(mystr.startswith('Check'))
True
True

3.5 Dictionaries: Use the default parameter of dict.get to provide default values

In [19]:
# WRONG
power = dict([('on', 100), ('off', 0)])
if 'idle' in power:
    print(power['idle'])
else:
    print(0.1)
0.1
In [20]:
# CORRECT
print(power.get('idle', 0.1))
0.1

3.6 File IO: Use Context Managers to ensure resources are properly managed

# WRONG - If the function 'do_something' generates an exception
#         the file will never be closed
file_handle = open('myfile', 'r')
for line in file_handle.readlines():
    do_something(line):
file_handle.close()

# CORRECT - Using 'with' you don''t need to explicitly call 'close'
with open('myfile', 'r') as file_handle:
    for line in file_handle.readlines():
        do_something(line):

4 Control Structures

4.1 Don't compare boolean values to True or False using ==

# WRONG
if condition == True:
if condition is True:

# CORRECT
if condition:
In [21]:
# Remember that empty strings, lists or tuples are false
mylist = [1, 2, 3]
if mylist:
    print('There is something to do!')
There is something to do!

4.2 Avoid placing conditional branch on the same line as the colon

# WRONG
if condition: print (something)

# CORRECT
if condition:
    print (something)

4.3 Comparisons to singletons like None should always be done with is or is not.

In [22]:
# WRONG
mytest = None
if mytest == None:
    print('This is wrong')

# CORRECT
if mytest is None:
    print('This is correct')
This is wrong
This is correct

4.4 Avoid repeating variable name in compound if Statement

In [23]:
a = 'two'
# WRONG
if a == 'one' or a == 'two' or a == 'three':
    print("This works but it's wrong")

# CORRECT
if a in ('one', 'two', 'three'):
    print('This is correct!')
This works but it's wrong
This is correct!

4.5 Use list comprehensions to create lists that are subsets of existing data

List comprehensions, when used judiciously, increase clarity in code that builds a list from existing data. Moreover list comprehensions can speed-up the code.

In [24]:
# WRONG
origin = range(1, 100)
mylist = list()
for item in origin:
    if not item%5:
        mylist.append(item+0.1)

# CORRECT
mylist = [item+0.1 for item in origin if not item%5]

4.6 Indexes in for Loops

Programmers coming from other languages are used to iterate over a container by accessing elements via index. Python's in keyword handles this gracefully.

In [25]:
mylist = ['a', 'b', 'c', 1, 2, 3]
# WRONG
index = 0
while index < len(mylist):
    print((mylist[index]), end=''),
    index+=1
    
print('\n')

# CORRECT
for item in mylist:
    print(item, end='')
abc123

abc123
In [26]:
# CORRECT - When the index is needed for any reason, use 'enumerate'
for index, item in enumerate(mylist):
    print(index, item, ' -- ', end='')
0 a  -- 1 b  -- 2 c  -- 3 1  -- 4 2  -- 5 3  -- 

4.7 range and xrange

In Python e3 range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists.

In [27]:
# IN PYTHON 3 THIS IS CORRECT
sum1 = 0
for x in range(5000*5000):
    sum1 = sum1+x
print('Sum1: {0:,d}'.format(sum1))
Sum1: 312,499,987,500,000

Visit www.add-for.com for more tutorials and updates.

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.