python tips, tricks & how-to’s

Some useful pythonic idioms I’ve learned along with simply useful code snippets.

Title Art

Random Walk from Patterns of the Universe. Given a grid of hexagons, assign a number and color to each of the six sides. Take a die and roll it to determine the next hexagon to fill in (and its color). Repeat. If you’re wondering why there are more than six colors, good eye! I whimsically rotated colors in and out. Colors by me.

Pythonic Idioms

Reverse a list
Slicing will return a new list but reversed. Using method .reverse() will flip the list in place.
>>> # create a simple test list
... my_list = [0, 1, 2, 3 , 4, 5]
>>> 
>>> # get a new reversed list using slicing
... reverse_list = my_list[::-1]
>>> my_list
[0, 1, 2, 3, 4, 5]
>>> reverse_list
[5, 4, 3, 2, 1, 0]
>>> 
>>> # or, reverse in place using .reverse()
... my_list.reverse()
>>> my_list
[5, 4, 3, 2, 1, 0]
List comprehension
Easily create a new custom list or filter an existing one with list comprehensions.
>>> # create a list with odd values between 1 and 10
... odd_list = [i for i in range(10) if i%2==1]
>>> odd_list
[1, 3, 5, 7, 9]
>>> 
>>> # square odd_list
... square_list = [i*i for i in odd_list]
>>> square_list
[1, 9, 25, 49, 81]

The general format is [EXPRESSION for ITEM in LIST if CONDITION]

Iterate list with a value and index
Python makes it really easy to iterate through a list, but sometimes I still need an index. Luckily enumerate() returns both index and value.
>>> # create a list of strings
... fruits = ['apple', 'orange', 'banana', 'mango']
>>> # iterate through list 
... for idx, ifruit in enumerate(fruits):
...     print("fruits[{}] = {}".format(idx, ifruit))
... 
fruits[0] = apple
fruits[1] = orange
fruits[2] = banana
fruits[3] = mango

When using a dictionary, use dict.items() instead of enumerate() to loop over key, value pairs.

Swap items in a single line
Python allows ‘multiple assignment’ where you can assign n values to n variables; multiple assignment feature also allows us to swap two or more items in a single line of code.
>>> # create two variables, with initial values using multiple assignment
>>> a, b = 2, 3 # a=2, b=3
>>> a
2
>>> b
3
>>> # swap values of a and b using multiple assignment again
>>> a, b = b, a
>>> a
3
>>> b
2
>>>
>>> # extends to N items and can be used with other objects like lists
>>> a, b, c = [0, 1, 2], [3, 4, 5], [6, 7, 8]
>>> print('a={}, b={}, c={}'.format(a, b, c))
a=[0, 1, 2], b=[3, 4, 5], c=[6, 7, 8]
>>> # rotate a, b, c lists (a=b, b=c, c=a)
>>> print('a={}, b={}, c={}'.format(a, b, c))
a=[3, 4, 5], b=[6, 7, 8], c=[0, 1, 2]
Default values when accessing dictionaries
A common use for dictionaries is to store a count for each word (or other item). When we want to include another word in the running counts, we need to first check if the word is in the dictionary to avoid errors, right? We could. Or we could use .get() with a default value!
>>> word_list = ['mango', 'banana', 'plum', 'pear', 'plum', 'apple', 'mango', 'plum', 'pear']
>>> word_counts = {} # initialize empty dictionary
>>> for w in word_list:
...     word_counts[w] = word_counts.get(w, 0) + 1 # if w not in dictionary, return 0
... 
>>> word_counts
{'mango': 2, 'banana': 1, 'plum': 3, 'pear': 2, 'apple': 1}

Python Data Structures

Modify a character in a string
Strings are immutable (i.e. can’t modify) in Python, but that doesn’t mean we’re stuck. Python makes it easy to convert a string to a list and back again.
>>> # as an example, let's use a word ladder to convert 'lost' to 'coal'
>>> str = 'lost'
>>> str_list = list(str)
>>> str_list
['l', 'o', 's', 't']
>>> str_list[0] = 'c' # turn 'lost' into 'cost'
>>> str_list
['c', 'o', 's', 't']
>>> str_list[2:] = ['a', 'l'] # do two steps in one to turn 'cost' into 'coal'
>>> str_list
['c', 'o', 'a', 'l']
>>> str = "".join(str_list) # convert list back into a string
>>> str
'coal'
Use Python’s built-in heap
Did you know Python has built-in support for heaps (aka priority queues)? It’s a great way to maintain relative order if, for example, you need to find the smallest item repeatedly. If you’re used to storing trees or heaps in an array, you won’t be surprised to learn that you can achieve heap functionality with a python list with heapq. Warning, the heapq methods modify your list.
>>> my_list = [15, 20, 8, 6, 4, 12, 3, 9]
>>> heapq.heapify(my_list) # put the list in approximate order (based on heap rules)
>>> my_list
[3, 4, 8, 6, 20, 12, 15, 9]
>>> heapq.heappush(my_list, 1) # add some items to the heap
>>> heapq.heappush(my_list, 2)
>>> my_list
[1, 2, 8, 4, 3, 12, 15, 9, 6, 20] # order is different!
>>> print('smallest item in heap = {}'.format(heapq.heappop(my_list)))
smallest item in heap = 1
>>> print('next 3 smallest items are: {}'.format(heapq.nsmallest(3, my_list)))
next 3 smallest items are: [2, 3, 4]
Merge two lists
When adding a single item to a list, you can use .append(). But if you need to add an entire list, use .extend().
>>> list1 = [0, 1, 2]
>>> list2 = [3, 4, 5]
>>> list1.extend(list2)
>>> list1
[0, 1, 2, 3, 4, 5]
Track insertion order in a dictionary with OrderedDict
Dictionaries (a.k.a. hashmaps) are awesome and very convenient, but the keys aren’t guaranteed to be in a particular order. Python has OrderedDict in collections that will keep keys in insertion order, in exchange for extra memory of course. Documentation here.
>>> from collections import OrderedDict
>>> ordered = OrderedDict()
>>> ordered.update({0:0, 1:1, 2:2, 3:3}) # merge two dictionaries with .update()
>>> ordered.keys()
odict_keys([0, 1, 2, 3])
>>> ordered[1] = 3
>>> ordered.keys()
odict_keys([0, 1, 2, 3]) # order hasn't changed
>>> ordered.move_to_end(1)
>>> ordered.keys()
odict_keys([0, 2, 3, 1]) # 1 is now at the end