Python 3

Table of Contents

References

Looping

Looping Backwards

Use reversed:

colors = ['red', 'green', 'blue']
 
for color in reversed(colors):
    print(color)

Looping Over Collection and Indices

Use enumerate:

colors = ['red', 'green', 'blue']
 
for i, color in enumerate(colors):
    print("{} -> {}".format(i, color))

Looping Over Two Collections

names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
 
for name, color in zip(names,colors):
    print("{} -> {}".format(name, color))

Note that the lengths are different.

Looping in Sorted Order

Use sorted:

colors = ['red', 'green', 'blue']
 
for color in sorted(colors):
    print(color)

To sort by length:

colors = ['red', 'green', 'blue']
 
for color in sorted(colors, key=len):
    print(color)

Breaking Out of Two Loops and Nested Loops

Python's break only breaks out of one loop. To break out from two, make it a single loop. So:

for x in range(width):
    for y in range(height):
        <do something>

Create a range:

def range_2d(width, height):
    for x in range(width):
        for y in range(height):
            yield x, y

Then, you can do:

for x, y in range_2d(width, height):
    <do something>

More Nested Loops

Instead of:

for i in v:
    for j in w:
        <do something>

you can do

it = ( (i,j) for i in v for j in w ) # creates a GENERATOR
for i,j in it:
    <do something>

Dictionaries

Looping Over Dictionary Keys

d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
 
for k in d:
    print k

If you want to change the dictionary while you loop, loop over d.keys():

for k in d.keys():
    if k.startswith('r'):
        del d[k]

Looping Over Dictionary Values

for v in d.values()
   <do stuff>

Looping Over Dictionary Items

for key, value in d.items()
    print("{} --> {}".format(key, value))

Construct Dictionaries from Pairs

d = dict(zip(names, colors))

Counting Occurrences

Use d.get. d.get(item,0) gives d[item] if possible and 0 otherwise.

d = {}
v = [0,0,0,1,1,1,1,1,1,2,2,0,2,1]
for x in v:
    d[x] = d.get(x,0) + 1

There is also d.setdefault(key, default_value), which also creates the d[key] if it does not exist already.

One can also use defaultdict(type), which creates an “empty” dictionary with values of type.

For instance, to create a dictionary grouping stings of names by length:

from collections import defaultdict
 
d = defaultdict(list)
for name in names:
    key = len(name)
    d[key].append(name)

If key does not exist, it creates it and sets the default value for list, which is an empty list. (And for int it is 0.)

Another Construction Example

v = [ 'a', 'b', 'c', 'd' ]
w = [ 1, 2, 3, 4 ]
my_dict = { letter : number for letter, number in zip(v,w) if number != 2 }

gives my_dict as { 'a' : 1, 'c' : 3, 'd' : 4 }.

Function Arguments

Optional Arguments

Use * for optional arguments with no default value.

def my_fct(x, *v):
    print('First value is {}'.format(x))
    if v: # runs if v is not empty
        print('The other values are:')
        for value in v:
            print(value)

You can call it with my_fct(3), my_fct(3,4), my_fct(3,4,5), etc.

Also, if v = [1, 2], then my_fct(3,*v) is the same as my_fct(3,1,2).

Required Keyword Arguments

In Python 3, if

def f(x, y, *, z=0, w=1):
    return x+y+z+w

you cannot call it as f(1,2,3,4), you must call it with f(1,2,x=3,w=4), i.e., the keyword arguments must be entered as keywords.

Misc Tricks

Lambda Functions

Instead of

def f(x,y):
    return x + y

do

f = lambda x, y: x + y

Map and Filter

If v is a list and f is a function, then

fv = map(f,v)

applies f to entries of v. In Python 3 it is iterable. (To make a list, do fv = list(map(v)).)

Now if test is a conditional function,

testv = filter(test,v)

gives only the elements of v satisfying test. Similar to

testv = [ x in v if test(x) ]

but in Python 3 it gives an iterable, not a list.

Avoid True/False Flags

You can use the else part of a for loop. So, instead of

def find(seq, target):
    found = False
    for i, value in enumerate(seq):
        if value == target:
            found = True
            break
    if not found:
        return -1
    return i

do

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            found = True
            break
    else:
        return -1
    return i

The else is like a nobreak: if the look finished normally, it skips the else part. If there is a break in the look, it runs the else part.

Caching

To save functions from recomputing the same value (with the expense of saving the computed values in memory) is to use@cache. So, instead of:

def my_fct(x, saved={}):
    if x in saved:
        return saved[x]
     <compute result>
     saved[x] = result
     return result

do

@cache
def my_fact(x):
    <compute result>
    return result

Open/Close Files

Instead of:

f = open('data.txt')
try:
    data = f.read()
finally:
    f.close()

do

with open('data.txt') as f:
    data = f.read()

Generator Expressions

Instead of

sum([i**2 for i in range(10)])

do

sum(i**2 for i in range(10))

Named Tuples

from collections import namedtuple
 
Color = namedtuple('Color',['hue', 'saturation', 'luminosity'])
 
p = Color(170, 0.1, 0.6)
 
if p.saturation > 0.5:
   print('Bright!')
 
if p.luminosity > 0.5:
    print('Light!')

See also: https://www.geeksforgeeks.org/namedtuple-in-python/

Generators

If you want to loop over the squares of integers from 1 to 1000, instead of creating the list

[ i**2 for i in range(1,1001)]

and looping, create the generator/iterator:

( i**2 for i in range(1,1001))

It's better in most cases to return generators/iterators instead of lists. So instead of:

def cubes(n):
    res = []
    for i in range(n):
        res.append(i**3)
    return res

you can do

def cubes(n):
    for i in range(n):
         yield i**3

We can make it a list if we want to with list(cubes(10)), but we can use to iterate (only once per call), like:

for i in cubes(10):
    <do something with i>

Or, to extract the first three elements:

c = cubes(100000)
next(c)
next(c)
next(c)

Conditional Assignment

x = 1 if <condition> else 0

Adding Commas to Printed Numbers

number = 100000000
print('The number is {:,}'.format(number))

Unpacking

a, b, c = (1, 2, 3, 4, 5)

gives an error. In Python 3 we can do

a, b, *c = (1, 2, 3, 4, 5)

gives an a = 1, b = 2, c = [3, 4, 5].

a, b, *_ = (1, 2, 3, 4, 5)

gives an a = 1 and b = 2.

a, b, *c, d  = (1, 2, 3, 4, 5)

gives an a = 1, b = 2, c = [3, 4], and d = 5.

Values Treated as False

The following values are treated as False: “” (empty string), 0, 0.0, [] (empty list), () (empty tuple), {} (empty dictionary), False, None. If variable then is any of those, then

if variable:
     print('OK')

will not print OK, but will otherwise.

Creating Empty Set

You cannot create and empty set wit my_set = {} as it creates an empty dictionary. So, you do it with my_set = set().

This also works for lists, tuples or dictionaries:

empty_list = []
empty_list = list()
 
empty_tuple = ()
empty_tuple = tuple()
 
empty_dict = {}
empty_dict = dict()