This page is designed to give you a list of concrete examples demonstrating idiomatic (Pythonic) code.
Many of the examples were taken from the following resources:
- PEP 8 - Style Guide for Python Code
- Khan Academy Style Guide
- Hitchikers Guide to Python
- Writing Idiomatic Python
- Python Best Practice Patterns
- Python-tips-tricks-and-idioms
- Little book of Python anti-paterns
Python philosophically distinguishes itself from other programming languages by it's particularly strong emphasis on readability –code that conforms itself to known best practices/standards.
Within the Python community, well written code is said to be "Pythonic" if it adheres to the Python philosophy. People who have mastered coding in a Pythonic way are known as "Pythonistas."
The most canonical example of the tenets that distinguish un-Pythonic from Pythonic code can be found in Tim Peters famous poem, "The Zen of Python." To read it you need only open a Python prompt on your command line, and type the words, "import this."
>>> 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!
The two lines most relevant to this page are
- Readability counts
- There should be one-- and preferably only one -- obvious way to do it
Indicate seperate words in variable names using underscores
my_variable_name = True
Indicate seperate words in function names using underscores
def my_function_name():
pass
Indicate seperate words in class names using CamelCase
class MyClassName(object):
pass
Prefix a single underscore to class members/functions meant for internal use only
class MyClassName(object):
def _internal_function(self):
pass
Use all caps to indicate constants
class ConnectDB(object):
DB = "mysql",
USER = "Steve",
PASS = "fzHx$"
def __init__(self):
pass
Use 4 spaces per indentation level
BAD
if x is True:
print(x)
GOOD
if x is True:
print(x)
Limit the length of your lines to 79 characters in width
BAD
def my_function(a, b, c):
my_str = "a, b, and c contains the following values {0}, {1}, {2}".format(a, b, c)
GOOD
def my_function(a, b, c):
my_str = "a, b, and c contains the following values {0}, {1}, {2}".format(
a, b, c)
Create readable multi-line text with the use of parentheses
BAD
big_string = """This is the first line in the text \
this is the second line in the text \
this is the third line in the text"""
GOOD
big_string = (
"This is the first line in the text "
"this is the second line in the text "
"this is the third line in the text"
)
In general, try to only import one module per line
BAD
import sys, os, requests
GOOD
import os
import sys
import requests
Avoid using a temporary variable when swapping two variables
BAD
c = a
a = b
b = c
GOOD
a, b = b, a
Use tuples to unpack data
BAD
li = [1, 2, 3]
a = li[0]
b = li[1]
c = li[2]
GOOD
li = [1, 2, 3]
(a, b, c) = li
Use ''.join() on an empty string to concatonate a collection of strings
BAD
li = ['a', 'b', 'c']
result = ''
for x in li:
result += x
GOOD
li = ['a', 'b', 'c']
result = ''.join(li)
Use dict.get() to return a default value from a dictionary
BAD
x = None
if 'item' in my_dict:
x = my_dict['item']
else:
x = 'fallback value'
GOOD
x = my_dict.get('item', 'fallback value')
Open files using using the with statement
BAD
f = open(path_to_file)
for line in f.readlines():
# do something...
f.close()
GOOD
with open(path_to_file) as f:
for line in f:
# do something...
# no need to call close()
Avoid repeating a variable within a compound if statement
BAD
if name=='Tom' or name=='Sam' or name=='Ron':
pass
GOOD
if name in ('Tom', 'Sam', 'Ron'):
pass
Don't place conditional code on the same line as the colon
BAD
if item: print(item)
GOOD
if item:
print(item)
Avoid putting multiple statements on a single line
BAD
if condition: my_function(); my_other_function();
GOOD
if condition:
my_function()
my_other_function()
Use list comprehensions to create lists that are subsets of existing data
BAD
l1 = range(1, 100)
l2 = []
for x in l1:
if is_prime(x):
l2.append(x)
GOOD
l1 = range(1, 100)
l2 = [x for x in l1 if is_prime(x)]
Use the 'in' keyword to iterate over an Iterable
BAD
li = ['a', 'b', 'c']
index = 0
while index < len(li):
print(li[index])
index += 1
GOOD
li = ['a', 'b', 'c']
for element in li:
print(element)
Use the 'enumerate' built-in function to keep count on an Iterable
BAD
li = ['a', 'b', 'c']
index = 0
for item in li:
print(index, item)
index += 1
GOOD
for index, item in enumerate(li):
print(index, item)
Create a length-N list composed of the same specific item
BAD
four_nones = []
for x in range(1,5):
four_nones.append(None)
GOOD
four_nones = [None] * 4
Create a length-N list composed of empty lists
BAD
li = []
for _ in range(1, 5):
li.append([])
GOOD
li = [[] for _ in range(4)]
Use isinstance() to do object type comparisons
BAD
x = 5
if type(x) is type(1):
print('x is an int')
GOOD
x = 5
if isinstance(x, int):
print('x is an int')
For strings, lists, and tuples, use the fact that empty sequences are false
BAD
x = []
if not len(x):
print('x is false')
GOOD
x = []
if not x:
print('x is false')
Avoid using a mutable values as a default function parameter
BAD
def fn(x=[]):
x.append(1)
print(x)
GOOD
def fn(x=None):
x = [] if x is None else x
x.append(1)
print(x)
Check that all items in a large set of items are true
BAD
if a and b and c and d and e and f and g and h:
print('all true')
GOOD
if all([a, b, c, d, e, f, g, h]):
print('all true')
Check if at least one item in a set of three or more items are true
BAD
if a or b or c:
print('at least one is true')
GOOD
if any([a, b, c]):
print('at least one is true')
Be careful how you use the is operator when checking for empty/unset variables.
Inherently falsy values like None, [], (), "", '', and 0 do not all mean the same thing.
BAD
import random
x = random.choice([ None, [] ])
if x is not None:
print(x)
# if x=[] then print(x) will run
GOOD
import random
x = random.choice([ None, [] ])
if x:
print(x)
# neither None or [] will pass the if statment
Be aware of scope. Using the same variable name for a global and local variables can lead to errors
BAD
x = 1
def fn():
print(x)
x = 2
fn() # UnboundLocalError: local variable 'x' referenced before assignment
print(x) # prints 1
GOOD
# things work as expected as long as we don't locally redfine x in the function scope
x = 1
def fn():
print(x)
y = 2
fn() # prints 1
print(x) # prints 1
# to modify the global variable x, you could do
x = 1
def fn():
global x
print(x)
x = 2
fn() # prints 1
print(x) # prints 2
Take advantage of extended slice notation to reverse a string
BAD
backward = ''
for c in reversed('hello'):
backward += c
print(backward) # 'olleh'
GOOD
# the faster albiet less readable approach is
backward = 'hello'[::-1]
# the slower but more readable approach is:
backward = ''.join(reversed('hello'))
print(backward) # 'olleh'
Counting frequency
BAD
ls = ['a', 'a', 'b', 'c', 'a']
foo = {}
for x in ls:
if x in foo:
foo[x] += 1
else:
foo[x] = 1
print(foo) # {'a': 3, 'b': 1, 'c': 1}
GOOD
from collections import Counter
ls = ['a', 'a', 'b', 'c', 'a']
foo = Counter(ls)
print(foo) # Counter({'a': 3, 'b': 1, 'c': 1})
Use for..else to run some code if the break statment is never reached. BAD
# bad example here that uses a tracking variable to determine if break has run or not
GOOD
for f in file_list:
if is_img(f):
break
else: # no break encountered
batch_process_files(file_list)
Add __repr__
to all your classes for more beautiful debugging
class Example:
def __init__(self, x):
self.x = x
def __repr__(self):
return 'Example(x={})'.format(self.x)
Use virtualenv
- don't install python packages at the system level
Take advantage of ipython/Juptyers profiling functions like %time
and %prun
to profile code.
Avoid *args
and **kwargs
unless you need them - they make function signatures hard to read and code-completion less helpful
Incorporate a linting tool like pyflakes
or pylint
into your IDE.
Learn to approach unit tests as a brain-storming exercise on how best to write your application.
In general prefer smaller individual functions dedicated to doing a single thing to larger functions that do many things.
Give every function a docstring.