Advanced Python Training at Arcesium - Day 1

Oct 22-24, 2018 Vikrant Patil

These notes are available online at http://notes.pipal.in/2018/arcesium-advanced-oct/day1.html

© Pipal Academy LLP

Day 1 | Day 2 | Day 3

We will be using python 3 (>= 3.0) from anaconda for this training. You can download it from

https://www.anaconda.com/download/

Warmup

In [1]:
digits = [0,1,2,3,4,5,6,7,8,9]
In [2]:
digits[0]
Out[2]:
0
In [3]:
digits[-1]
Out[3]:
9
In [4]:
digits[2:4]
Out[4]:
[2, 3]
In [7]:
digits[:2] #take first two
Out[7]:
[0, 1]
In [8]:
x = [1,2,3]
y = [-1,-2,-3]
z = [0]*5
a = [1]*5
In [9]:
collection = [x,y,z,a]
In [10]:
subview = collection[1:2]
In [11]:
subview
Out[11]:
[[-1, -2, -3]]
In [12]:
collection
Out[12]:
[[1, 2, 3], [-1, -2, -3], [0, 0, 0, 0, 0], [1, 1, 1, 1, 1]]
In [13]:
subview
Out[13]:
[[-1, -2, -3]]
In [14]:
[collection[1]]
Out[14]:
[[-1, -2, -3]]
In [15]:
y.append(-4)
In [16]:
y
Out[16]:
[-1, -2, -3, -4]
In [17]:
collection
Out[17]:
[[1, 2, 3], [-1, -2, -3, -4], [0, 0, 0, 0, 0], [1, 1, 1, 1, 1]]
In [18]:
subview
Out[18]:
[[-1, -2, -3, -4]]
In [19]:
digits[2:]# drop first two
Out[19]:
[2, 3, 4, 5, 6, 7, 8, 9]
In [20]:
digits[:2] = []
In [21]:
digits
Out[21]:
[2, 3, 4, 5, 6, 7, 8, 9]
In [22]:
list(range(10))
Out[22]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [23]:
list(range(2,10))
Out[23]:
[2, 3, 4, 5, 6, 7, 8, 9]
In [24]:
list(range(2,10,2))
Out[24]:
[2, 4, 6, 8]
In [25]:
digits[2:9:2]
Out[25]:
[4, 6, 8]
In [26]:
digits = list(range(10))
In [27]:
digits[2:9:2]
Out[27]:
[2, 4, 6, 8]
In [28]:
digits[::2]
Out[28]:
[0, 2, 4, 6, 8]
In [29]:
digits[::-1]
Out[29]:
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

problem

  • Write a function to check wheather given word is palindrome or not
In [30]:
digits[2:5:-1]
Out[30]:
[]
In [31]:
digits[8:3:-1]
Out[31]:
[8, 7, 6, 5, 4]
In [32]:
def is_palindrome(word):
    return word == word[::-1]
In [33]:
is_palindrome("madam")
Out[33]:
True
In [34]:
for i in range(0,10,1):
    print(i, end=",")
0,1,2,3,4,5,6,7,8,9,
In [35]:
squares = []
for d in digits:
    squares.append(d*d)
In [36]:
squares
Out[36]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
In [37]:
[d*d for d in squares]
Out[37]:
[0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]
In [39]:
def even(x):
    return x%2==0

squares = []
for d in digits:
    if even(d):
        squares.append(d*d)
    
In [40]:
squares
Out[40]:
[0, 4, 16, 36, 64]
In [41]:
[d*d for d in digits if even(d)]
Out[41]:
[0, 4, 16, 36, 64]
In [42]:
[e for e in digits if even(e)]
Out[42]:
[0, 2, 4, 6, 8]

problem

  • write a function to access column from 2d list
In [43]:
data = [[1,1,1],
        [2,2,2],
        [3,3,3]]
In [44]:
data
Out[44]:
[[1, 1, 1], [2, 2, 2], [3, 3, 3]]
In [45]:
data[0]
Out[45]:
[1, 1, 1]
In [46]:
data[-1]
Out[46]:
[3, 3, 3]
In [ ]:
 
In [47]:
data[0][0]
Out[47]:
1
In [48]:
data[0][1]
Out[48]:
1
In [49]:
data[0][2]
Out[49]:
1
In [50]:
data[0]
Out[50]:
[1, 1, 1]
In [51]:
row0 = data[0]
In [52]:
row0[0]
Out[52]:
1
In [53]:
def column(data, n):
    return [row[n] for row in data]
In [54]:
column(data, 0)
Out[54]:
[1, 2, 3]

problem

  • Write a function to find transpose of a 2d list
In [55]:
def transpose(data):
    cols = len(data[0])
    return [column(data, c) for c in range(cols)]
In [56]:
transpose(data)
Out[56]:
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
In [57]:
data
Out[57]:
[[1, 1, 1], [2, 2, 2], [3, 3, 3]]
In [58]:
if data:
    print("List is nonempty")
else:
    pass
List is nonempty
In [59]:
%%file data.csv
A1,A2,A3
B1,B2,B3
C1,C2,C3
Writing data.csv
In [62]:
csvdata = []
with open("data.csv") as csv:
    for line in csv:
        csvdata.append(line.strip().split(","))
In [63]:
csvdata
Out[63]:
[['A1', 'A2', 'A3'], ['B1', 'B2', 'B3'], ['C1', 'C2', 'C3']]
In [63]:
csvdata
Out[63]:
[['A1', 'A2', 'A3'], ['B1', 'B2', 'B3'], ['C1', 'C2', 'C3']]
In [64]:
def csvparser(filename):
    with open(filename) as f:
        return [line.strip().split(",") for line in f]
In [65]:
csvparser("data.csv")
Out[65]:
[['A1', 'A2', 'A3'], ['B1', 'B2', 'B3'], ['C1', 'C2', 'C3']]
In [69]:
def quick(data):
    if not data:
        return []
    
    pivot = data[0]
    
    less = [n for n in data[1:] if n < pivot]
    greater = [n for n in data[1:] if n>= pivot]
    
    return quick(less) + [pivot] + quick(greater)
In [70]:
quick([2,5,1,7,9,2,34,3,4])
Out[70]:
[1, 2, 2, 3, 4, 5, 7, 9, 34]
In [71]:
sorted([2,3,4,1,6,23,56])
Out[71]:
[1, 2, 3, 4, 6, 23, 56]

Functions

Positional Arguments

Positional arguments work by position. you can not misplace the order of arguments

In [72]:
def cylinder_volume(radius, height):
    return 3.14*radius**2*height
In [73]:
cylinder_volume(1,1)
Out[73]:
3.14
In [74]:
cylinder_volume(1,10) 
Out[74]:
31.400000000000002
In [76]:
cylinder_volume(10, 1) # if arguments are given in different order you get different result
Out[76]:
314.0

Named arguments

In [77]:
def cylinder_volume(radius, height):
    return 3.14*radius**2*height
In [78]:
cylinder_volume(radius=1.0, height=10)
Out[78]:
31.400000000000002
In [79]:
cylinder_volume(height=10, radius=1.0)
Out[79]:
31.400000000000002

default arguments

In [80]:
def cylinder_volume(radius=1.0, height=1.0):
    return 3.14*radius**2*height
In [81]:
cylinder_volume()
Out[81]:
3.14
In [82]:
list(range(10))
Out[82]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [83]:
import os
In [84]:
os.listdir()
Out[84]:
['.ipynb_checkpoints',
 'push',
 'day1.ipynb',
 'Makefile~',
 'day2.ipynb',
 'day2.html',
 'day3.ipynb',
 'data.csv',
 'day3.html',
 'Makefile',
 'day1.html']
In [85]:
os.listdir("/tmp/")
Out[85]:
['Temp-a21992e3-047a-437b-9de2-7080c5b00b70',
 'config-err-P74Phw',
 '.XIM-unix',
 'babel-4144NcV',
 '.font-unix',
 'systemd-private-67c157d0da4c4465a1e74816ea45d4ec-colord.service-PEqv1E',
 'systemd-private-67c157d0da4c4465a1e74816ea45d4ec-rtkit-daemon.service-UFslbf',
 '.ICE-unix',
 '.X11-unix',
 '.X0-lock',
 '.Test-unix',
 'ssh-asEt1PNHpq9u',
 'mintUpdate']
In [86]:
import random

def jitter(n, delta=random.random()):
    return n+delta
    
In [87]:
random.random()
Out[87]:
0.45221824635253205
In [88]:
for item in [100, 101, 125, 130]:
    print(jitter(item))
100.50297384128969
101.50297384128969
125.50297384128969
130.50297384128967
In [91]:
def jitter(n, delta=None):
    if not delta:
        delta = random.random()
    return n+delta
In [92]:
for item in [100, 101, 125, 130]:
    print(jitter(item))
100.55010745848246
101.69511934909961
125.26391968596852
130.60716186974972

Even if you want to have muttable objects as default arguments , initialize it to None

In [96]:
def append(value, collection=None):
    if not collection:
        collection = []
    collection.append(value)
    return collection
In [97]:
x = [1,2,3]
append(10,collection=x)
Out[97]:
[1, 2, 3, 10]
In [98]:
x
Out[98]:
[1, 2, 3, 10]
In [99]:
append(11)
Out[99]:
[11]
In [100]:
def add(a=0, b):
    return a+b
  File "<ipython-input-100-5f2b873e8607>", line 1
    def add(a=0, b):
           ^
SyntaxError: non-default argument follows default argument
In [101]:
def adder(x=5, y =3):
    return x+y
In [102]:
adder()
Out[102]:
8
In [103]:
adder(2)
Out[103]:
5
In [104]:
adder(y=5)
Out[104]:
10

Named only arguments

In [105]:
def foo(x,y, *, name="bar"):
    pass
In [106]:
foo(2,3)
In [107]:
foo(2,3,"python")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-107-31b6ed39ee1e> in <module>()
----> 1 foo(2,3,"python")

TypeError: foo() takes 2 positional arguments but 3 were given
In [108]:
foo(2,3,name="python")
In [109]:
def foo(x,y, *, data="bar"):
    pass
In [110]:
foo(1,2,data="xyz")
In [111]:
foo(1,2,bar=3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-111-1fdc852633d6> in <module>()
----> 1 foo(1,2,bar=3)

TypeError: foo() got an unexpected keyword argument 'bar'
In [114]:
def foo (x,y,data="bar"):
    pass
In [113]:
foo(2,3,"python")
In [116]:
def fun(*, x, y, data="bar"):
    pass
In [117]:
fun(x=1,y=3)
In [118]:
fun(1,3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-118-3d42148f8ceb> in <module>()
----> 1 fun(1,3)

TypeError: fun() takes 0 positional arguments but 2 were given

Variable number of arguments

In [119]:
import os.path
In [120]:
os.path.join("/","home","vikrant")
Out[120]:
'/home/vikrant'
In [121]:
"_".join(["A","B","C"])
Out[121]:
'A_B_C'
In [122]:
os.path.join("/","home","vikrant","trainings")
Out[122]:
'/home/vikrant/trainings'
In [123]:
def myjoin(*args):
    sep = "/"
    return sep.join(args)
In [124]:
myjoin("z","y","z")
Out[124]:
'z/y/z'
In [125]:
d = ["a","b","c","d"]
In [126]:
myjoin(d)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-126-65f8836db206> in <module>()
----> 1 myjoin(d)

<ipython-input-123-2c4f2eb833b8> in myjoin(*args)
      1 def myjoin(*args):
      2     sep = "/"
----> 3     return sep.join(args)

TypeError: sequence item 0: expected str instance, list found
In [127]:
myjoin(*d)
Out[127]:
'a/b/c/d'

Variable number of keyword arguments

In [132]:
def make_person(**metadata):
    print(type(metadata))
    person = {}
    for key, value in metadata.items():
        person[key] = value
    return person
In [133]:
make_person(name="python", email="python@python.org", web="www.python.org")
<class 'dict'>
Out[133]:
{'email': 'python@python.org', 'name': 'python', 'web': 'www.python.org'}

Functions as arguments

In [134]:
def fun():
    print("fun!")
In [135]:
print(fun)
<function fun at 0x7fbd400f0510>
In [136]:
x = 2
In [137]:
print(x)
2
In [138]:
y = x
In [139]:
aliasfun = fun
In [140]:
print(aliasfun)
<function fun at 0x7fbd400f0510>
In [141]:
fun
Out[141]:
<function __main__.fun>
In [142]:
aliasfun
Out[142]:
<function __main__.fun>
In [143]:
fun()
fun!
In [144]:
aliasfun()
fun!
In [145]:
def square(x):
    return x*x
In [146]:
def sumofsquares(x,y):
    return square(x) + square(y)
In [147]:
def cube(x):
    return x*x*x

def sumofcubes(x,y):
    return cube(x) + cube(y)
In [148]:
def sumof(f, x, y):
    return f(x) + f(y)
In [149]:
sumof(square, 3, 5)
Out[149]:
34
In [150]:
sumofsquares(3,5)
Out[150]:
34
In [151]:
max([3,4,5,1,78,32])
Out[151]:
78
In [152]:
words = ["one","two","three","four","five"]
In [153]:
max(words)
Out[153]:
'two'
In [154]:
max(words, key=len)
Out[154]:
'three'
In [155]:
sorted(words)
Out[155]:
['five', 'four', 'one', 'three', 'two']
In [157]:
sorted(words, key=len)
Out[157]:
['one', 'two', 'four', 'five', 'three']
In [158]:
def sumf(f, start, end):
    s = 0
    for i in range(start, end):
        s += f(i)
    return s
8/1*3 + 8/5*7 + 8/9*11 ..... this series slowly converges to pi
In [159]:
def f(n):
    return 8/((4*n-3)*(4*n-1))
In [160]:
sumf(f, 1, 1000)
Out[160]:
3.1410921531206317

Functions as return value

In [161]:
def make_adder(x):
    
    def adder(y):
        return x+y
    
    return adder
In [162]:
adder5 = make_adder(5)
In [163]:
adder5
Out[163]:
<function __main__.make_adder.<locals>.adder>
In [164]:
adder5(8)
Out[164]:
13
In [165]:
adder5(3)
Out[165]:
8
In [166]:
adder7 = make_adder(7)
In [167]:
adder7(5)
Out[167]:
12
In [168]:
adder7(8)
Out[168]:
15
In [170]:
add = lambda x, y: x+y
In [171]:
add(3,4)
Out[171]:
7
In [172]:
sumf(lambda n: 8/((4*n-3)*(4*n-1)), 1, 1000)
Out[172]:
3.1410921531206317

problems

  • Write a function repeat which applies given function n times.
  • Write a function repeat_ which returns a function which when called is equivalent to calling a function n times.
In [173]:
def repeat(f, n, arg):
    res = f(arg)
    for i in range(n-1):
        res = f(res)
    return res

def repeat_(f, n):
    def repeter(x):
        for i in range(n):
            x = f(x)
        return x
    return repeter

Decorators

In [174]:
def add(x, y):
    return x+y
In [175]:
def debug(f):
    
    def wrapper(*args):
        print("Begining ", f.__qualname__, args)
        r = f(*args)
        print("Returning", r)
        return r
    return wrapper
        
In [176]:
add_ = debug(add)
In [177]:
add_(2,3)
Begining  add (2, 3)
Returning 5
Out[177]:
5
In [178]:
add = debug(add)
In [179]:
add(3,4)
Begining  add (3, 4)
Returning 7
Out[179]:
7
In [180]:
@debug
def square(x):
    return x*x
In [181]:
def sumofsquares(x, y):
    return square(x) + square(y)
In [182]:
sumofsquares(5,6)
Begining  square (5,)
Returning 25
Begining  square (6,)
Returning 36
Out[182]:
61
In [183]:
(1,)
Out[183]:
(1,)
In [184]:
(1,2)
Out[184]:
(1, 2)
In [185]:
(1,)*2
Out[185]:
(1, 1)
In [192]:
level = 0 

def trace(f):
    
    def wrapper(*args):
        global level
        print(" |"*level + "-" + f.__qualname__, *args)
        level += 1
        r = f(*args)
        print(" |"*level + "-return", r)
        level -=1
        return r
    
    return wrapper
In [193]:
@trace
def square(x):
    return x*x
@trace
def sumofsquares(x,y):
    return square(x) + square(y)
In [194]:
sumofsquares(5,6)
-sumofsquares 5 6
 |-square 5
 | |-return 25
 |-square 6
 | |-return 36
 |-return 61
Out[194]:
61
In [205]:
def fib(n):
    if n in [1,2]:
        return 1
    else:
        return fib(n-1) + fib(n-2)
In [209]:
for i in range(1,10):
    print(fib(i), end=",")
1,1,2,3,5,8,13,21,34,
In [210]:
@trace
def fib(n):
    if n in [1,2]:
        return 1
    else:
        return fib(n-1) + fib(n-2)
In [212]:
fib(5)
-fib 5
 |-fib 4
 | |-fib 3
 | | |-fib 2
 | | | |-return 1
 | | |-fib 1
 | | | |-return 1
 | | |-return 2
 | |-fib 2
 | | |-return 1
 | |-return 3
 |-fib 3
 | |-fib 2
 | | |-return 1
 | |-fib 1
 | | |-return 1
 | |-return 2
 |-return 5
Out[212]:
5
In [213]:
fib(8)
-fib 8
 |-fib 7
 | |-fib 6
 | | |-fib 5
 | | | |-fib 4
 | | | | |-fib 3
 | | | | | |-fib 2
 | | | | | | |-return 1
 | | | | | |-fib 1
 | | | | | | |-return 1
 | | | | | |-return 2
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-return 3
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-return 5
 | | |-fib 4
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-fib 2
 | | | | |-return 1
 | | | |-return 3
 | | |-return 8
 | |-fib 5
 | | |-fib 4
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-fib 2
 | | | | |-return 1
 | | | |-return 3
 | | |-fib 3
 | | | |-fib 2
 | | | | |-return 1
 | | | |-fib 1
 | | | | |-return 1
 | | | |-return 2
 | | |-return 5
 | |-return 13
 |-fib 6
 | |-fib 5
 | | |-fib 4
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-fib 2
 | | | | |-return 1
 | | | |-return 3
 | | |-fib 3
 | | | |-fib 2
 | | | | |-return 1
 | | | |-fib 1
 | | | | |-return 1
 | | | |-return 2
 | | |-return 5
 | |-fib 4
 | | |-fib 3
 | | | |-fib 2
 | | | | |-return 1
 | | | |-fib 1
 | | | | |-return 1
 | | | |-return 2
 | | |-fib 2
 | | | |-return 1
 | | |-return 3
 | |-return 8
 |-return 21
Out[213]:
21

problem

  • Write a decorator deprecated which displays depricated warning message when the function is called
  • Write a decorator timeit which will time given function call use time.time() to get current timestamp
  • Write a decorator with_retries which calls given function five times before giving up!
In [214]:
import time
In [215]:
def timeit(f):
    
    def wrapper(*args):
        start = time.time()
        r = f(*args)
        print("Time taken:",time.time()-start)
        return r
    return wrapper
In [219]:
def fib_(n):
    if n in [1,2]:
        return 1
    else:
        return fib_(n-1) + fib_(n-2)
    
@timeit
def fibcaller(n):
    return fib_(n)
In [226]:
fibcaller(35)
Time taken: 4.326493263244629
Out[226]:
9227465
In [257]:
%%file memoize.py
from functools import wraps


def memoize(f):
    
    cache = {}
    @wraps(f)
    def wrapper(*args):
        if args not in cache:
            cache[args] = f(*args)
        return cache[args]
    return wrapper
Overwriting memoize.py
In [258]:
import imp
imp.reload(memoize)
Out[258]:
<module 'memoize' from '/home/vikrant/trainings/2018/arcesium-advanced-oct/memoize.py'>
In [259]:
import memoize
In [260]:
@memoize.memoize
def square(x):
    print("Calling square", x)
    return x*x

def sumofsquares(x,y):
    return square(x) + square(y)
In [261]:
sumofsquares(2,3)
Calling square 2
Calling square 3
Out[261]:
13
In [262]:
sumofsquares(3,2)
Out[262]:
13
In [263]:
@trace
@memoize.memoize
def fib1(n):
    if n in [1,2]:
        return 1
    else:
        return fib1(n-1) + fib1(n-2)
In [264]:
fib1(8)
-fib1 8
 |-fib1 7
 | |-fib1 6
 | | |-fib1 5
 | | | |-fib1 4
 | | | | |-fib1 3
 | | | | | |-fib1 2
 | | | | | | |-return 1
 | | | | | |-fib1 1
 | | | | | | |-return 1
 | | | | | |-return 2
 | | | | |-fib1 2
 | | | | | |-return 1
 | | | | |-return 3
 | | | |-fib1 3
 | | | | |-return 2
 | | | |-return 5
 | | |-fib1 4
 | | | |-return 3
 | | |-return 8
 | |-fib1 5
 | | |-return 5
 | |-return 13
 |-fib1 6
 | |-return 8
 |-return 21
Out[264]:
21
In [265]:
fib(8)
-fib 8
 |-fib 7
 | |-fib 6
 | | |-fib 5
 | | | |-fib 4
 | | | | |-fib 3
 | | | | | |-fib 2
 | | | | | | |-return 1
 | | | | | |-fib 1
 | | | | | | |-return 1
 | | | | | |-return 2
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-return 3
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-return 5
 | | |-fib 4
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-fib 2
 | | | | |-return 1
 | | | |-return 3
 | | |-return 8
 | |-fib 5
 | | |-fib 4
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-fib 2
 | | | | |-return 1
 | | | |-return 3
 | | |-fib 3
 | | | |-fib 2
 | | | | |-return 1
 | | | |-fib 1
 | | | | |-return 1
 | | | |-return 2
 | | |-return 5
 | |-return 13
 |-fib 6
 | |-fib 5
 | | |-fib 4
 | | | |-fib 3
 | | | | |-fib 2
 | | | | | |-return 1
 | | | | |-fib 1
 | | | | | |-return 1
 | | | | |-return 2
 | | | |-fib 2
 | | | | |-return 1
 | | | |-return 3
 | | |-fib 3
 | | | |-fib 2
 | | | | |-return 1
 | | | |-fib 1
 | | | | |-return 1
 | | | |-return 2
 | | |-return 5
 | |-fib 4
 | | |-fib 3
 | | | |-fib 2
 | | | | |-return 1
 | | | |-fib 1
 | | | | |-return 1
 | | | |-return 2
 | | |-fib 2
 | | | |-return 1
 | | |-return 3
 | |-return 8
 |-return 21
Out[265]:
21
In [248]:
@memoize.memoize
def fib1(n):
    if n in [1,2]:
        return 1
    else:
        return fib1(n-1) + fib1(n-2)

@timeit
def fibcaller(n):
    return fib1(n)
In [249]:
fibcaller(35)
Time taken: 8.249282836914062e-05
Out[249]:
40434438
In [256]:
fibcaller(50)
Time taken: 1.1682510375976562e-05
Out[256]:
55152603076

decoartors with parameters

In [266]:
from functools import wraps

def with_retries(f):
    
    @wraps(f)
    def wrapper(*args):
        for i in range(5):
            try:
                return f(*args)
            except Exception as e:
                print(e, "retrying...", i+1)
        print("Giving up!")
    
    return wrapper
                
In [268]:
import requests
@with_retries
def download(url):
    r = requests.get(url)
    return r.status_code==200
In [269]:
download("http://xyz.skjdlkaslsbd.dkjfhkjsd.com/dsd")
HTTPConnectionPool(host='xyz.skjdlkaslsbd.dkjfhkjsd.com', port=80): Max retries exceeded with url: /dsd (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd3859ec88>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 1
HTTPConnectionPool(host='xyz.skjdlkaslsbd.dkjfhkjsd.com', port=80): Max retries exceeded with url: /dsd (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd385220b8>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 2
HTTPConnectionPool(host='xyz.skjdlkaslsbd.dkjfhkjsd.com', port=80): Max retries exceeded with url: /dsd (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd38522128>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 3
HTTPConnectionPool(host='xyz.skjdlkaslsbd.dkjfhkjsd.com', port=80): Max retries exceeded with url: /dsd (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd3859eb38>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 4
HTTPConnectionPool(host='xyz.skjdlkaslsbd.dkjfhkjsd.com', port=80): Max retries exceeded with url: /dsd (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd3859edd8>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 5
Giving up!
In [270]:
from functools import wraps

def with_retries(tries=5):
    def _with_retries(f):
    
        @wraps(f)
        def wrapper(*args):
            for i in range(tries):
                try:
                    return f(*args)
                except Exception as e:
                    print(e, "retrying...", i+1)
            print("Giving up!")
    
        return wrapper
    
    return _with_retries


@with_retries(tries=3)
def download(url):
    r = requests.get(url)
    return r.status_code==200
In [272]:
download("http://hsjhdkasj")
HTTPConnectionPool(host='hsjhdkasj', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd3852bd68>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 1
HTTPConnectionPool(host='hsjhdkasj', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd3852b6d8>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 2
HTTPConnectionPool(host='hsjhdkasj', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7fbd3852bc88>: Failed to establish a new connection: [Errno -2] Name or service not known',)) retrying... 3
Giving up!

Working with json

In [273]:
import json
In [275]:
jsonstring = json.dumps({"name":"alice", "email":"alice@wonder.land"})
In [276]:
jsonstring
Out[276]:
'{"name": "alice", "email": "alice@wonder.land"}'
In [277]:
json.loads(jsonstring)
Out[277]:
{'email': 'alice@wonder.land', 'name': 'alice'}
In [278]:
import requests
In [279]:
url = "https://api.github.com/orgs/{}/repos".format("google")
In [280]:
url
Out[280]:
'https://api.github.com/orgs/google/repos'
In [281]:
repos = requests.get(url).json()
In [282]:
type(repos)
Out[282]:
list
In [283]:
len(repos)
Out[283]:
30
In [284]:
repos[0]
Out[284]:
{'archive_url': 'https://api.github.com/repos/google/upb/{archive_format}{/ref}',
 'archived': False,
 'assignees_url': 'https://api.github.com/repos/google/upb/assignees{/user}',
 'blobs_url': 'https://api.github.com/repos/google/upb/git/blobs{/sha}',
 'branches_url': 'https://api.github.com/repos/google/upb/branches{/branch}',
 'clone_url': 'https://github.com/google/upb.git',
 'collaborators_url': 'https://api.github.com/repos/google/upb/collaborators{/collaborator}',
 'comments_url': 'https://api.github.com/repos/google/upb/comments{/number}',
 'commits_url': 'https://api.github.com/repos/google/upb/commits{/sha}',
 'compare_url': 'https://api.github.com/repos/google/upb/compare/{base}...{head}',
 'contents_url': 'https://api.github.com/repos/google/upb/contents/{+path}',
 'contributors_url': 'https://api.github.com/repos/google/upb/contributors',
 'created_at': '2009-05-09T02:38:42Z',
 'default_branch': 'master',
 'deployments_url': 'https://api.github.com/repos/google/upb/deployments',
 'description': 'a small protobuf implementation in C',
 'downloads_url': 'https://api.github.com/repos/google/upb/downloads',
 'events_url': 'https://api.github.com/repos/google/upb/events',
 'fork': False,
 'forks': 123,
 'forks_count': 123,
 'forks_url': 'https://api.github.com/repos/google/upb/forks',
 'full_name': 'google/upb',
 'git_commits_url': 'https://api.github.com/repos/google/upb/git/commits{/sha}',
 'git_refs_url': 'https://api.github.com/repos/google/upb/git/refs{/sha}',
 'git_tags_url': 'https://api.github.com/repos/google/upb/git/tags{/sha}',
 'git_url': 'git://github.com/google/upb.git',
 'has_downloads': True,
 'has_issues': True,
 'has_pages': True,
 'has_projects': True,
 'has_wiki': True,
 'homepage': '',
 'hooks_url': 'https://api.github.com/repos/google/upb/hooks',
 'html_url': 'https://github.com/google/upb',
 'id': 196334,
 'issue_comment_url': 'https://api.github.com/repos/google/upb/issues/comments{/number}',
 'issue_events_url': 'https://api.github.com/repos/google/upb/issues/events{/number}',
 'issues_url': 'https://api.github.com/repos/google/upb/issues{/number}',
 'keys_url': 'https://api.github.com/repos/google/upb/keys{/key_id}',
 'labels_url': 'https://api.github.com/repos/google/upb/labels{/name}',
 'language': 'C',
 'languages_url': 'https://api.github.com/repos/google/upb/languages',
 'license': {'key': 'other',
  'name': 'Other',
  'node_id': 'MDc6TGljZW5zZTA=',
  'spdx_id': 'NOASSERTION',
  'url': None},
 'merges_url': 'https://api.github.com/repos/google/upb/merges',
 'milestones_url': 'https://api.github.com/repos/google/upb/milestones{/number}',
 'mirror_url': None,
 'name': 'upb',
 'node_id': 'MDEwOlJlcG9zaXRvcnkxOTYzMzQ=',
 'notifications_url': 'https://api.github.com/repos/google/upb/notifications{?since,all,participating}',
 'open_issues': 23,
 'open_issues_count': 23,
 'owner': {'avatar_url': 'https://avatars1.githubusercontent.com/u/1342004?v=4',
  'events_url': 'https://api.github.com/users/google/events{/privacy}',
  'followers_url': 'https://api.github.com/users/google/followers',
  'following_url': 'https://api.github.com/users/google/following{/other_user}',
  'gists_url': 'https://api.github.com/users/google/gists{/gist_id}',
  'gravatar_id': '',
  'html_url': 'https://github.com/google',
  'id': 1342004,
  'login': 'google',
  'node_id': 'MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=',
  'organizations_url': 'https://api.github.com/users/google/orgs',
  'received_events_url': 'https://api.github.com/users/google/received_events',
  'repos_url': 'https://api.github.com/users/google/repos',
  'site_admin': False,
  'starred_url': 'https://api.github.com/users/google/starred{/owner}{/repo}',
  'subscriptions_url': 'https://api.github.com/users/google/subscriptions',
  'type': 'Organization',
  'url': 'https://api.github.com/users/google'},
 'permissions': {'admin': False, 'pull': True, 'push': False},
 'private': False,
 'pulls_url': 'https://api.github.com/repos/google/upb/pulls{/number}',
 'pushed_at': '2018-10-05T18:12:24Z',
 'releases_url': 'https://api.github.com/repos/google/upb/releases{/id}',
 'size': 5364,
 'ssh_url': 'git@github.com:google/upb.git',
 'stargazers_count': 915,
 'stargazers_url': 'https://api.github.com/repos/google/upb/stargazers',
 'statuses_url': 'https://api.github.com/repos/google/upb/statuses/{sha}',
 'subscribers_url': 'https://api.github.com/repos/google/upb/subscribers',
 'subscription_url': 'https://api.github.com/repos/google/upb/subscription',
 'svn_url': 'https://github.com/google/upb',
 'tags_url': 'https://api.github.com/repos/google/upb/tags',
 'teams_url': 'https://api.github.com/repos/google/upb/teams',
 'trees_url': 'https://api.github.com/repos/google/upb/git/trees{/sha}',
 'updated_at': '2018-10-19T05:13:11Z',
 'url': 'https://api.github.com/repos/google/upb',
 'watchers': 915,
 'watchers_count': 915}
In [285]:
for r in repos:
    print(r['full_name'], r['forks'])
google/upb 123
google/truth 166
google/ruby-openid-apps-discovery 16
google/autoparse 33
google/gitkit-ruby 0
google/anvil-build 15
google/googletv-android-samples 75
google/ChannelPlate 8
google/GL-Shader-Validator 12
google/qpp 7
google/CSP-Validator 12
google/embed-dart-vm 17
google/module-server 45
google/cxx-std-draft 12
google/filesystem-proposal 10
google/libcxx 36
google/tracing-framework 215
google/namebench 88
google/devtoolsExtended 18
google/sirius 0
google/testRunner 8
google/crx2app 11
google/episodes.dart 20
google/cpp-netlib 53
google/dagger 1479
google/ios-webkit-debug-proxy 339
google/google.github.io 39
google/kratu 30
google/build-debian-cloud 21
google/traceur-compiler 576
In [286]:
def get_forks(r):
    return r['forks']

for r in sorted(repos, key=get_forks, reverse=True)[:5]:
    print(r['name'], r['forks'])
dagger 1479
traceur-compiler 576
ios-webkit-debug-proxy 339
tracing-framework 215
truth 166

XML

In [287]:
url = "http://www.thehindu.com/"
In [289]:
response = requests.get(url, params={"service":"rss"})
In [290]:
xmltext = response.text
In [291]:
print(xmltext[:100])
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>The Hindu
In [292]:
from xml.etree import ElementTree as et
In [293]:
root = et.fromstring(xmltext)
In [294]:
items = root.findall(".//item")
In [295]:
len(items)
Out[295]:
100
In [296]:
items[0]
Out[296]:
<Element 'item' at 0x7fbd397411d8>
In [297]:
print(et.tostring(items[0]).decode())
<item>
            <title>Pakistan Army hands over administrative control of Swat district to civil authorities </title>
            <author>AP</author>
            <category>International</category>
            <link>https://www.thehindu.com/news/international/pakistan-army-hands-over-administrative-control-of-swat-district-to-civil-authorities/article25286787.ece</link>
            <description>
                 The Pakistan Army on Monday handed over the administrative control of the restive Swat district to the civil authorities, ending its decade-long mili
            </description>
            <pubDate>Mon, 22 Oct 2018 16:39:44 +0530</pubDate>
        </item>
        
In [298]:
for item in items[:10]:
    print(item.findtext("title"))
    print(item.findtext("link"))
    print("--"*20)
Pakistan Army hands over administrative control of Swat district to civil authorities 
https://www.thehindu.com/news/international/pakistan-army-hands-over-administrative-control-of-swat-district-to-civil-authorities/article25286787.ece
----------------------------------------
Play it safe with the 10.or D2
https://www.thehindu.com/sci-tech/technology/10or-d2-smartphone-play-it-safe-review/article25286774.ece
----------------------------------------
HC transfers missing techie case to CBI
https://www.thehindu.com/news/national/karnataka/hc-transfers-missing-techie-case-to-cbi/article25286710.ece
----------------------------------------
In the driver’s seat 
https://www.thehindu.com/news/cities/bangalore/in-the-drivers-seat/article25286700.ece
----------------------------------------
Turning a new leaf 
https://www.thehindu.com/books/books-authors/turning-a-new-leaf/article25286674.ece
----------------------------------------
Four earthquakes strike off Canada’s west coast 
https://www.thehindu.com/news/international/four-earthquakes-strike-off-canadas-west-coast/article25286649.ece
----------------------------------------
I want to make music that excites me, says singer Ranjith
https://www.thehindu.com/entertainment/movies/singer-ranjith-interview/article25286608.ece
----------------------------------------
Theresa May pleads for support, says Brexit deal is almost done 
https://www.thehindu.com/news/international/theresa-may-pleads-for-support-says-brexit-deal-is-almost-done/article25286566.ece
----------------------------------------
HP Omen X review: Performance at a price 
https://www.thehindu.com/sci-tech/technology/gadgets/hp-omen-x-review-performance-at-a-price/article25286219.ece
----------------------------------------
Suresh Nambath appointed as the next Editor of 'The Hindu'
https://www.thehindu.com/news/national/suresh-nambath-appointed-as-the-next-editor-of-the-hindu/article25286067.ece
----------------------------------------
In [299]:
from xml.dom.minidom import parseString
In [300]:
root = parseString(xmltext)
In [301]:
root
Out[301]:
<xml.dom.minidom.Document at 0x7fbd27884a08>
In [302]:
items = root.getElementsByTagName("item")
In [303]:
len(items)
Out[303]:
100
In [305]:
item = items[0]
In [309]:
title = item.getElementsByTagName("title")[0]
In [310]:
title.firstChild.data
Out[310]:
'Pakistan Army hands over administrative control of Swat district to civil authorities '
In [312]:
for item in items[:10]:
    title = item.getElementsByTagName("title")[0]
    link = item.getElementsByTagName("link")[0]
    print(title.firstChild.data)
    print(link.firstChild.data)
    print("-"*10)
Pakistan Army hands over administrative control of Swat district to civil authorities 
https://www.thehindu.com/news/international/pakistan-army-hands-over-administrative-control-of-swat-district-to-civil-authorities/article25286787.ece
----------
Play it safe with the 10.or D2
https://www.thehindu.com/sci-tech/technology/10or-d2-smartphone-play-it-safe-review/article25286774.ece
----------
HC transfers missing techie case to CBI
https://www.thehindu.com/news/national/karnataka/hc-transfers-missing-techie-case-to-cbi/article25286710.ece
----------
In the driver’s seat 
https://www.thehindu.com/news/cities/bangalore/in-the-drivers-seat/article25286700.ece
----------
Turning a new leaf 
https://www.thehindu.com/books/books-authors/turning-a-new-leaf/article25286674.ece
----------
Four earthquakes strike off Canada’s west coast 
https://www.thehindu.com/news/international/four-earthquakes-strike-off-canadas-west-coast/article25286649.ece
----------
I want to make music that excites me, says singer Ranjith
https://www.thehindu.com/entertainment/movies/singer-ranjith-interview/article25286608.ece
----------
Theresa May pleads for support, says Brexit deal is almost done 
https://www.thehindu.com/news/international/theresa-may-pleads-for-support-says-brexit-deal-is-almost-done/article25286566.ece
----------
HP Omen X review: Performance at a price 
https://www.thehindu.com/sci-tech/technology/gadgets/hp-omen-x-review-performance-at-a-price/article25286219.ece
----------
Suresh Nambath appointed as the next Editor of 'The Hindu'
https://www.thehindu.com/news/national/suresh-nambath-appointed-as-the-next-editor-of-the-hindu/article25286067.ece
----------

Database

In [313]:
import sqlite3
In [314]:
conn = sqlite3.connect("data.db") #:memory:
In [315]:
cur = conn.cursor()
In [317]:
cur.execute("create table person (name varchar(100), email varchar(100))")
Out[317]:
<sqlite3.Cursor at 0x7fbd380a6d50>
In [318]:
cur.execute("insert into person(name, email) values('alice', 'alice@wonder.land')")
Out[318]:
<sqlite3.Cursor at 0x7fbd380a6d50>
In [319]:
cur = cur.execute("select * from person")
In [320]:
cur.fetchall()
Out[320]:
[('alice', 'alice@wonder.land')]
In [321]:
def find_person(conn , email):
    q = "select * from person where email='{}'".format(email)
    cur = conn.cursor()
    return cur.execute(q).fetchall()
    
In [323]:
find_person(conn, "alice@wonder.land")
Out[323]:
[('alice', 'alice@wonder.land')]
In [324]:
def find_person(conn , email):
    q = "select * from person where email=?"
    cur = conn.cursor()
    return cur.execute(q, (email,)).fetchall()
In [325]:
find_person(conn, "alice@wonder.land")
Out[325]:
[('alice', 'alice@wonder.land')]
In [326]:
cur.close()
In [327]:
cur.execute("select * from person")
---------------------------------------------------------------------------
ProgrammingError                          Traceback (most recent call last)
<ipython-input-327-b8a66466bcd7> in <module>()
----> 1 cur.execute("select * from person")

ProgrammingError: Cannot operate on a closed cursor.
In [328]:
cur = conn.cursor()
In [329]:
cur.execute("select * from person")
Out[329]:
<sqlite3.Cursor at 0x7fbd3940e880>
In [330]:
cur = conn.cursor()
In [332]:
q = "select * from person where email like ?"
cur.execute(q, ("%alice%",)).fetchall()
Out[332]:
[('alice', 'alice@wonder.land')]

sqlalchemy

In [333]:
from sqlalchemy import Table , Column, Integer, String, MetaData, ForeignKey, create_engine
In [342]:
metadata = MetaData()
In [343]:
users = Table('users', metadata,
              Column('id', Integer, primary_key=True),
              Column('name', String),
              Column("email", String))
posts = Table("posts", metadata, 
              Column('id', Integer, primary_key=True),
              Column("author_id", Integer, ForeignKey('users.id')),
              Column("title", String),
              Column("body", String))
In [336]:
engine = create_engine("sqlite:///test.db", echo=True)
metadata.create_all(engine)
2018-10-22 17:26:27,910 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2018-10-22 17:26:27,912 INFO sqlalchemy.engine.base.Engine ()
2018-10-22 17:26:27,915 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2018-10-22 17:26:27,916 INFO sqlalchemy.engine.base.Engine ()
2018-10-22 17:26:27,919 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users")
2018-10-22 17:26:27,920 INFO sqlalchemy.engine.base.Engine ()
2018-10-22 17:26:27,923 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("posts")
2018-10-22 17:26:27,924 INFO sqlalchemy.engine.base.Engine ()
2018-10-22 17:26:27,926 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE users (
	id INTEGER NOT NULL, 
	name VARCHAR, 
	email VARCHAR, 
	PRIMARY KEY (id)
)


2018-10-22 17:26:27,927 INFO sqlalchemy.engine.base.Engine ()
2018-10-22 17:26:27,936 INFO sqlalchemy.engine.base.Engine COMMIT
2018-10-22 17:26:27,938 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE posts (
	id INTEGER NOT NULL, 
	author_id INTEGER, 
	title VARCHAR, 
	body VARCHAR, 
	PRIMARY KEY (id), 
	FOREIGN KEY(author_id) REFERENCES users (id)
)


2018-10-22 17:26:27,939 INFO sqlalchemy.engine.base.Engine ()
2018-10-22 17:26:27,948 INFO sqlalchemy.engine.base.Engine COMMIT
In [346]:
q = users.insert().values(name="Alice", email="alice@wonder.land")
metadata.bind = engine
q.execute()
2018-10-22 17:35:50,865 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, email) VALUES (?, ?)
2018-10-22 17:35:50,871 INFO sqlalchemy.engine.base.Engine ('Alice', 'alice@wonder.land')
2018-10-22 17:35:50,878 INFO sqlalchemy.engine.base.Engine COMMIT
Out[346]:
<sqlalchemy.engine.result.ResultProxy at 0x7fbd25f75668>
In [347]:
results = users.select().execute()
2018-10-22 17:35:51,556 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.email 
FROM users
2018-10-22 17:35:51,561 INFO sqlalchemy.engine.base.Engine ()
In [348]:
results.fetchall()
Out[348]:
[(1, 'Alice', 'alice@wonder.land'), (2, 'Alice', 'alice@wonder.land')]
In [349]:
select = users.select()
In [350]:
select.where(users.columns.name=="Alice").execute().fetchall()
2018-10-22 17:35:53,676 INFO sqlalchemy.engine.base.Engine SELECT users.id, users.name, users.email 
FROM users 
WHERE users.name = ?
2018-10-22 17:35:53,680 INFO sqlalchemy.engine.base.Engine ('Alice',)
Out[350]:
[(1, 'Alice', 'alice@wonder.land'), (2, 'Alice', 'alice@wonder.land')]

Object Relational Mapping ORM

In [352]:
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, create_engine

from sqlalchemy.ext.declarative import declarative_base

engine = create_engine("sqlite:///test.db")
Base = declarative_base()
Base.metadata.bind = engine
In [353]:
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)
    
    def __repr__(self):
        return "User({0},{1})".format(self.name, self.email)
    
class Post(Base):
    __tablename__ = "posts"
    id = Column(Integer, primary_key=True)
    author_id = Column(Integer, ForeignKey("users.id"))
    title  = Column(String)
    body = Column(String)
    
    def __repr__(self):
        return "Post({author}, {title})".format(author=self.author_id, title=self.title)
In [354]:
from sqlalchemy.orm import sessionmaker
DBSession = sessionmaker(bind=engine)
session = DBSession()
In [355]:
new_user = User(name="anand", email="anand@xyz.com")
session.add(new_user)
session.commit()
In [356]:
q = session.query(User)
print(q.all())
[User(Alice,alice@wonder.land), User(Alice,alice@wonder.land), User(anand,anand@xyz.com)]
In [ ]: