A Crash Course in Python

The Basics

The Zen of Python


In [1]:
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!

Whitespace Formatting


In [7]:
for i in [1, 2, 3, 4, 5]:
    print(i)
    for j in [1, 2, 3, 4, 5]:
        print(j)
        print(i + j)
    print(i)
print('done looping')


1
1
2
2
3
3
4
4
5
5
6
1
2
1
3
2
4
3
5
4
6
5
7
2
3
1
4
2
5
3
6
4
7
5
8
3
4
1
5
2
6
3
7
4
8
5
9
4
5
1
6
2
7
3
8
4
9
5
10
5
done looping

In [8]:
long_winded_computation = (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 +
                           13 + 14 + 15 + 16 + 17 + 18 + 19 + 20)

In [9]:
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [10]:
easier_to_read_list_of_lists = [ [1, 2, 3],
                                 [4, 5, 6],
                                 [7, 8, 9] ]

In [11]:
two_plus_three = 2 + \
                 3

Modules


In [13]:
import re

In [14]:
my_regex = re.compile("[0-9]+", re.I)

Functions


In [16]:
def double(x):
    return x * 2

In [17]:
def apply_to_one(f):
    return f(1)

In [18]:
my_double = double

In [19]:
x = apply_to_one(my_double)

In [20]:
x


Out[20]:
2

In [21]:
def my_print(message='my default message'):
    print(message)

In [22]:
my_print('hello world!')


hello world!

In [23]:
my_print()


my default message

In [24]:
def substract(a=0, b=0):
    return a - b

In [25]:
substract(10, 5)


Out[25]:
5

In [26]:
substract(0, 5)


Out[26]:
-5

In [27]:
substract(4)


Out[27]:
4

In [28]:
substract(b=2)


Out[28]:
-2

Strings


In [29]:
single_quoted_string = 'data science'

In [30]:
double_quoted_strng = "data science"

In [31]:
tab_string = '\t'

In [32]:
len(tab_string)


Out[32]:
1

In [34]:
print(tab_string)


	

In [35]:
not_tab_string = r'/t'

In [36]:
len(not_tab_string)


Out[36]:
2

In [37]:
print(not_tab_string)


/t

In [39]:
multi_line_string = """This is the first line.
and this is the second line
and this is the third line"""

In [40]:
multi_line_string


Out[40]:
'This is the first line.\nand this is the second line\nand this is the third line'

In [41]:
print(multi_line_string)


This is the first line.
and this is the second line
and this is the third line

Exceptions


In [44]:
try:
    print(0 / 0)
except ZeroDivisionError:
    print('cannot divide by zero')


cannot divide by zero

Lists


In [45]:
integer_list = [1, 2, 3]
heterogeneous_list = ['string', 0.1, True]

In [46]:
list_of_lists = [integer_list, heterogeneous_list, []]

In [47]:
list_length = len(integer_list)

In [48]:
list_sum = sum(integer_list)

In [49]:
1 in [1, 2, 3]


Out[49]:
True

In [50]:
0 in [1, 2, 3]


Out[50]:
False

In [51]:
x = [1, 2, 3]
x.extend([4, 5, 6])

In [52]:
x


Out[52]:
[1, 2, 3, 4, 5, 6]

In [53]:
y = x + [7, 8, 9]

In [54]:
y


Out[54]:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

In [55]:
y.append(0)

In [56]:
y


Out[56]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

In [57]:
x[-1]


Out[57]:
6

In [58]:
len(x)


Out[58]:
6

In [59]:
a, b = [1, 3]

In [60]:
b


Out[60]:
3

In [61]:
a


Out[61]:
1

In [63]:
_, c =[2, 4]

In [64]:
c


Out[64]:
4

Tuples


In [65]:
my_tuple = (1, 2)

In [66]:
my_tuple


Out[66]:
(1, 2)

In [67]:
other_tuple = 3, 4

In [68]:
other_tuple


Out[68]:
(3, 4)

In [69]:
my_tuple[1]


Out[69]:
2

In [70]:
try:
    my_tuple[0] = 2
except TypeError:
    print('cannot modify a tuple')


cannot modify a tuple

In [71]:
def sum_and_product(x, y):
    return (x + y), (x * y)

In [72]:
sum_and_product(2, 3)


Out[72]:
(5, 6)

In [73]:
sum_and_product(5, 10)


Out[73]:
(15, 50)

In [74]:
m, n = 2, 3

In [75]:
m, n = n, m

In [76]:
m


Out[76]:
3

In [77]:
n


Out[77]:
2

Dictionaries


In [78]:
empty_dict = {}
empty_dict2 = dict()
grades = {"Joel": 80, "Tim": 95}

In [79]:
grades["Joel"]


Out[79]:
80

In [80]:
try:
    kates_grade = grades['Kate']
except KeyError:
    print('no grade for Kate!')


no grade for Kate!

In [81]:
'Joel' in grades


Out[81]:
True

In [82]:
'Kate' in grades


Out[82]:
False

In [83]:
grades.get('Joel', 0)


Out[83]:
80

In [84]:
grades.get('Kate', 0)


Out[84]:
0

In [85]:
grades.get('No One')

In [86]:
grades['Tim'] = 99
grades['Kate'] = 95
len(grades)


Out[86]:
3

In [88]:
tweet = {
    'user': 'joelgrus',
    'text': 'Data Science is Awesome',
    'retweet_count': 100,
    'hashtags': ['#data', '#science', '#datascience', '#awesome', '#yolo']
}

In [89]:
tweet_keys = tweet.keys()
tweet_values = tweet.values()
tweet_items = tweet.items()

In [90]:
'user' in tweet_keys


Out[90]:
True

In [91]:
'user' in tweet


Out[91]:
True

In [92]:
100 in tweet


Out[92]:
False

In [93]:
'joelgrus' in tweet_values


Out[93]:
True

defaultdict


In [96]:
from collections import defaultdict

In [97]:
dd_list = defaultdict(list)
dd_list[2].append(1)

In [98]:
dd_list


Out[98]:
defaultdict(list, {2: [1]})

In [99]:
dd_dict = defaultdict(dict)
dd_dict['Joel']['City'] = 'Seattle'

In [100]:
dd_dict


Out[100]:
defaultdict(dict, {'Joel': {'City': 'Seattle'}})

In [101]:
dd_pair = defaultdict(lambda: [0, 0])
dd_pair[2][1] = 1

In [102]:
dd_pair


Out[102]:
defaultdict(<function __main__.<lambda>>, {2: [0, 1]})

Counter


In [103]:
from collections import Counter

In [104]:
c = Counter([0, 1, 2, 0, 2, 2, 4, 1])

In [105]:
c


Out[105]:
Counter({0: 2, 1: 2, 2: 3, 4: 1})

In [110]:
for num, count in c.most_common():
    print(num, count)


2 3
0 2
1 2
4 1

Sets


In [111]:
s = set()
s.add(1)
print(s)
s.add(2)
print(s)
s.add(2)
print(s)
x = len(s)
print(x)


{1}
{1, 2}
{1, 2}
2

In [112]:
2 in s


Out[112]:
True

In [113]:
3 in s


Out[113]:
False

Control Flow

Truthiness


In [114]:
all([])


Out[114]:
True

In [116]:
any([])


Out[116]:
False

The Not-So-Basics

Sorting


In [117]:
x = [4, 1, 2, 3]

In [118]:
y = sorted(x)

In [119]:
y


Out[119]:
[1, 2, 3, 4]

In [120]:
x.sort()

In [121]:
x


Out[121]:
[1, 2, 3, 4]

In [122]:
x = sorted([-4, 1, -2, 3], key=abs, reverse=True)

In [123]:
x


Out[123]:
[-4, 3, -2, 1]

List Comprehensions


In [124]:
even_numbers = [x for x in range(5) if x % 2 == 0]

In [126]:
even_numbers


Out[126]:
[0, 2, 4]

In [127]:
squares = [x * x for x in range(5)]

In [128]:
squares


Out[128]:
[0, 1, 4, 9, 16]

In [129]:
even_squares = [x * x for x in range(5) if x % 2 == 0]

In [130]:
even_squares


Out[130]:
[0, 4, 16]

In [131]:
square_dict = {x : x * x for x in range(5)}

In [132]:
square_dict


Out[132]:
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

In [133]:
square_set = {x * x for x in [-1, 1, 2]}

In [134]:
square_set


Out[134]:
{1, 4}

In [135]:
zeroes = [0 for _ in even_numbers]

In [136]:
zeroes


Out[136]:
[0, 0, 0]

In [137]:
pairs = [(x, y) for x in range(10) for y in range(22)]

In [138]:
pairs


Out[138]:
[(0, 0),
 (0, 1),
 (0, 2),
 (0, 3),
 (0, 4),
 (0, 5),
 (0, 6),
 (0, 7),
 (0, 8),
 (0, 9),
 (0, 10),
 (0, 11),
 (0, 12),
 (0, 13),
 (0, 14),
 (0, 15),
 (0, 16),
 (0, 17),
 (0, 18),
 (0, 19),
 (0, 20),
 (0, 21),
 (1, 0),
 (1, 1),
 (1, 2),
 (1, 3),
 (1, 4),
 (1, 5),
 (1, 6),
 (1, 7),
 (1, 8),
 (1, 9),
 (1, 10),
 (1, 11),
 (1, 12),
 (1, 13),
 (1, 14),
 (1, 15),
 (1, 16),
 (1, 17),
 (1, 18),
 (1, 19),
 (1, 20),
 (1, 21),
 (2, 0),
 (2, 1),
 (2, 2),
 (2, 3),
 (2, 4),
 (2, 5),
 (2, 6),
 (2, 7),
 (2, 8),
 (2, 9),
 (2, 10),
 (2, 11),
 (2, 12),
 (2, 13),
 (2, 14),
 (2, 15),
 (2, 16),
 (2, 17),
 (2, 18),
 (2, 19),
 (2, 20),
 (2, 21),
 (3, 0),
 (3, 1),
 (3, 2),
 (3, 3),
 (3, 4),
 (3, 5),
 (3, 6),
 (3, 7),
 (3, 8),
 (3, 9),
 (3, 10),
 (3, 11),
 (3, 12),
 (3, 13),
 (3, 14),
 (3, 15),
 (3, 16),
 (3, 17),
 (3, 18),
 (3, 19),
 (3, 20),
 (3, 21),
 (4, 0),
 (4, 1),
 (4, 2),
 (4, 3),
 (4, 4),
 (4, 5),
 (4, 6),
 (4, 7),
 (4, 8),
 (4, 9),
 (4, 10),
 (4, 11),
 (4, 12),
 (4, 13),
 (4, 14),
 (4, 15),
 (4, 16),
 (4, 17),
 (4, 18),
 (4, 19),
 (4, 20),
 (4, 21),
 (5, 0),
 (5, 1),
 (5, 2),
 (5, 3),
 (5, 4),
 (5, 5),
 (5, 6),
 (5, 7),
 (5, 8),
 (5, 9),
 (5, 10),
 (5, 11),
 (5, 12),
 (5, 13),
 (5, 14),
 (5, 15),
 (5, 16),
 (5, 17),
 (5, 18),
 (5, 19),
 (5, 20),
 (5, 21),
 (6, 0),
 (6, 1),
 (6, 2),
 (6, 3),
 (6, 4),
 (6, 5),
 (6, 6),
 (6, 7),
 (6, 8),
 (6, 9),
 (6, 10),
 (6, 11),
 (6, 12),
 (6, 13),
 (6, 14),
 (6, 15),
 (6, 16),
 (6, 17),
 (6, 18),
 (6, 19),
 (6, 20),
 (6, 21),
 (7, 0),
 (7, 1),
 (7, 2),
 (7, 3),
 (7, 4),
 (7, 5),
 (7, 6),
 (7, 7),
 (7, 8),
 (7, 9),
 (7, 10),
 (7, 11),
 (7, 12),
 (7, 13),
 (7, 14),
 (7, 15),
 (7, 16),
 (7, 17),
 (7, 18),
 (7, 19),
 (7, 20),
 (7, 21),
 (8, 0),
 (8, 1),
 (8, 2),
 (8, 3),
 (8, 4),
 (8, 5),
 (8, 6),
 (8, 7),
 (8, 8),
 (8, 9),
 (8, 10),
 (8, 11),
 (8, 12),
 (8, 13),
 (8, 14),
 (8, 15),
 (8, 16),
 (8, 17),
 (8, 18),
 (8, 19),
 (8, 20),
 (8, 21),
 (9, 0),
 (9, 1),
 (9, 2),
 (9, 3),
 (9, 4),
 (9, 5),
 (9, 6),
 (9, 7),
 (9, 8),
 (9, 9),
 (9, 10),
 (9, 11),
 (9, 12),
 (9, 13),
 (9, 14),
 (9, 15),
 (9, 16),
 (9, 17),
 (9, 18),
 (9, 19),
 (9, 20),
 (9, 21)]

In [139]:
increasing_pairs = [(x, y) for x in range(10) for y in range(x + 1, 10)]

In [140]:
increasing_pairs


Out[140]:
[(0, 1),
 (0, 2),
 (0, 3),
 (0, 4),
 (0, 5),
 (0, 6),
 (0, 7),
 (0, 8),
 (0, 9),
 (1, 2),
 (1, 3),
 (1, 4),
 (1, 5),
 (1, 6),
 (1, 7),
 (1, 8),
 (1, 9),
 (2, 3),
 (2, 4),
 (2, 5),
 (2, 6),
 (2, 7),
 (2, 8),
 (2, 9),
 (3, 4),
 (3, 5),
 (3, 6),
 (3, 7),
 (3, 8),
 (3, 9),
 (4, 5),
 (4, 6),
 (4, 7),
 (4, 8),
 (4, 9),
 (5, 6),
 (5, 7),
 (5, 8),
 (5, 9),
 (6, 7),
 (6, 8),
 (6, 9),
 (7, 8),
 (7, 9),
 (8, 9)]

Generators and Iterators


In [141]:
def lazy_range(n):
    """a lazy version of range"""
    i = 0
    while i < n:
        yield i
        i += 1

In [142]:
lazy_range(10)


Out[142]:
<generator object lazy_range at 0x10645ebf8>

In [143]:
for i in lazy_range(10):
    print(i + 2)


2
3
4
5
6
7
8
9
10
11

Randomness


In [144]:
import random

In [145]:
four_uniform_rand = [random.random() for _ in range(4)]

In [146]:
four_uniform_rand


Out[146]:
[0.18412794649172415,
 0.3213248640315449,
 0.5525791373103462,
 0.8093409120910208]

In [147]:
random.random()


Out[147]:
0.3510362880837449

In [148]:
random.random()


Out[148]:
0.8388449430687542

In [149]:
random.seed(10)
random.random()


Out[149]:
0.5714025946899135

In [150]:
random.random()


Out[150]:
0.4288890546751146

In [151]:
random.seed(10)
random.random()


Out[151]:
0.5714025946899135

In [152]:
random.randrange(10)


Out[152]:
6

In [153]:
random.randrange(3,6)


Out[153]:
4

In [169]:
zero_ten = list(range(11))

In [170]:
random.shuffle(zero_ten)

In [171]:
print(zero_ten)


[7, 5, 8, 4, 2, 6, 1, 3, 10, 9, 0]

In [174]:
random.choice(zero_ten)


Out[174]:
3

In [175]:
lottery_numbers = list(range(60))

In [176]:
winning_numbers = random.sample(lottery_numbers, 6)

In [177]:
winning_numbers


Out[177]:
[27, 30, 4, 41, 37, 20]

In [179]:
[random.choice(lottery_numbers) for _ in range(6)]


Out[179]:
[15, 2, 2, 31, 19, 52]

Regular Expressions


In [180]:
import re

In [181]:
print(all([
            not re.match('a', 'cat'),
            re.search('a', 'cat'),
            not re.search('c', 'dog'),
            3 == len(re.split('[ab]', 'carbs')),
            'R-D-' == re.sub('[0-9]', '-', 'R2D2')
        ]))


True

Object-Oriented Programming

Functional Tools


In [1]:
def exp(base, power):
    return base ** power

In [2]:
def two_to_the(power):
    return exp(2, power)

In [3]:
from functools import partial

In [4]:
two_to_the = partial(exp, 2)

In [5]:
print(two_to_the(3))


8

In [6]:
square_of = partial(exp, power=2)

In [7]:
print(square_of(3))


9

In [8]:
def double(x):
    return 2 * x

In [9]:
xs = [1, 2, 3, 4]

In [10]:
twice_xs = [double(x) for x in xs]

In [11]:
twice_xs


Out[11]:
[2, 4, 6, 8]

In [13]:
list(map(double, xs))


Out[13]:
[2, 4, 6, 8]

In [14]:
list_doubler = partial(map, double)

In [16]:
list(list_doubler(xs))


Out[16]:
[2, 4, 6, 8]

In [17]:
def multiply(x, y): return x * y

In [18]:
products = map(multiply, [1, 2], [4, 5])

In [20]:
list(products)


Out[20]:
[4, 10]

In [21]:
def is_even(x):
    return x % 2 == 0

In [22]:
x_evens = [x for x in xs if is_even(x)]

In [23]:
x_evens


Out[23]:
[2, 4]

In [25]:
list(filter(is_even, xs))


Out[25]:
[2, 4]

In [26]:
list_evener = partial(filter, is_even)

In [27]:
list(list_evener(xs))


Out[27]:
[2, 4]

enumerate

zip and Argument Unpacking


In [29]:
list1 = ['a', 'b', 'c']
list2 = [1, 2, 3]

In [32]:
pairs = list(zip(list1, list2))
pairs


Out[32]:
[('a', 1), ('b', 2), ('c', 3)]

In [35]:
list(zip(*pairs))


Out[35]:
[('a', 'b', 'c'), (1, 2, 3)]

In [36]:
def add(a, b):
    return a + b

In [37]:
add(1, 2)


Out[37]:
3

In [39]:
add(*[1, 2])


Out[39]:
3

args and kwargs


In [40]:
def magic(*args, **kwargs):
    print('unnamed args:', args)
    print('keyword args:', kwargs)

In [41]:
magic(1, 2, key='word', key2='word2')


unnamed args: (1, 2)
keyword args: {'key2': 'word2', 'key': 'word'}

In [42]:
def other_way_magic(x, y, z):
    return x + y + z

In [43]:
x_y_list = [1, 2]

In [44]:
z_dict = {'z': 3}

In [46]:
other_way_magic(*x_y_list, **z_dict)


Out[46]:
6

In [47]:
def doubler_correct(f):
    def g(*args, **kwargs):
        return 2 * f(*args, **kwargs)
    return g

In [48]:
def f2(x, y):
    return x + y

In [49]:
g = doubler_correct(f2)

In [53]:
g(1, 2)


Out[53]:
6

In [ ]: