Sep 25-27, 2019 Vikrant Patil
These notes are available online at http://notes.pipal.in/2019/arcesium_advanced_sep/day1.html
© Pipal Academy LLP
We will be using python 3 (>= 3.0) from anaconda for this training. You can download it from
digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
digits[0]
digits[-1]
digits[2:6]
digits[:]
digits[3:] #drop first three
digits[:5]
digits[2:7:2]
digits[::2]
digits[:-5]
digits[-5:]
digits[::-1]
def is_palindrom(word):
return word == word[::-1]
is_palindrom("madam")
table = [[1,1,1],[2,2,2],[3,3,3]]
table[0]
table[-1]
for i in range(5):
print(i)
range(5)
list(range(5))
nums = [3, 5, 1, 7, 6]
sqr = []
for n in nums:
sqr.append(n*n)
print(sqr)
[n*n for n in nums]
s = [n*n for n in nums]
s
es = [n*n for n in nums if n%2==0]
es
table
matrix = [[1,1,1],[2,2,2],[3,3,3]]
def column(data, colnum):
pass
matrix[0]
matrix[0][0]
matrix[1][0]
matrix[2][0]
def column(data, colnum):
rowcount = len(data)
return [data[row][colnum] for row in range(rowcount)]
def transpose(data):
colcount = len(data[0])
return [column(data, c) for c in range(colcount)]
transpose(matrix)
def column(data, colnum):
return [row[colnum] for row in data]
%%file data.csv
A1,A2,A3
B1,B3,B3
C1,C2,C3
def csvparser(filename):
with open(filename) as f:
csvdata = []
for line in f:
csvdata.append(line.strip().split(","))
return csvdata
csvparser("data.csv")
def csvparser(filename):
with open(filename) as f:
return [line.strip().split(",") for line in f]
def qsort(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 qsort(less) + [pivot] + qsort(greater)
qsort([343,34,1,3,23,6,778,3])
qsort([])
qsort([1,2,3,4,5])
qsort(list(reversed(range(5))))
def cylinder_volume(radius, height):
return 3.14*radius**2*height
cylinder_volume(1.0, 10)
cylinder_volume(10, 1.0)
cylinder_volume(radius=1.0, height=10)
cylinder_volume(height=10, radius=1)
"*"**2
"#"*2
cylinder_volume(1, height=10)
cylinder_volume(height=10, 1)
Named argumnets can only follow after all positional arguments are over. After named argument you can not give postional argument
def cylinder_volume(radius=1.0, height=1.0):
return 3.14*radius**2*height
cylinder_volume()
cylinder_volume(radius=5)
cylinder_volume(height=10)
cylinder_volume(3) #radius 3 and height as default
import random
def jitter(data, dev=random.random()):
return data + dev
for n in [23,45,6,3]:
print(jitter(n))
def jitter1(data, dev=None):
if not dev:
dev = random.random()
return data + dev
for n in range(5):
print(jitter1(n))
def collection(data, default=[]):
default.extend(data)
return default
def collection1(data, default=None):
if not default:
default = []
default.extend(data)
return default
collection([1,2,3], default=[1,1,1])
collection([1,2,3])
collection([1,1,1])
collection1([1,2,3])
collection1([1,1,1])
words = ["hello", "welcome", "Namaskar", "Ramram"]
max(words)
max(words, key=len)
max(words, len)
def foo(x, y, *, name="bar"):
pass
foo(1,2)
foo(1,2,"hello")
foo(3, 4, name="hello")
def bar(x,y,*,name):
pass
bar(1,2)
bar(1, 2, name="hello")
import this
import os.path
os.path.join("/","home","vikrant","training")
os.path.join("/","home","vikrant")
def myjoin(*args):
sep = "_"
return sep.join(args)
myjoin("a","b","c","d","e")
d = ['x','y','z','m']
myjoin(*d)
def mysum(*args):
s = 0
for item in args:
s += item
return s
list(zip([1,2,3,4],['a','b','c','d']))
matrix
list(zip([1,2],['a','b'],['x',['y']]))
def transpose(data):
return list(zip(*data))
transpose(matrix)
matrix
def make_person(**kwargs):
return {"Arcesium_"+k:v for k, v in kwargs.items()}
make_person(name="Praveen", surname="Nair")
def foo(a, b, *args, **kwargs):
print("a,b ", a, b)
print(args)
print(kwargs)
foo(1, 2, 'x','y', name="xyz", greet="hello")
min(words, key=len)
sorted(words, key=len)
records = [
("HCL", 500.0, 10.0),
("INFY", 800.0, 8.0),
("TATA", 247, 3),
("MM", 530, -5)
]
def getprice(r):
return r[1]
lambda r: r[1]
max(records, key=lambda r:r[1])
max(records, key=lambda r:r[2])
def column(colnum):
return lambda r: r[colnum]
max(records, key=column(1))
max(records, key=column(2))
problem
repeat which takes a function as first argument, initial value as second argument, and an integer as third argument. repeat must apply function to initial value n times.
>>> repeat(lambda x:2*x, 1, 5)
32
compose , which composes two functions.
>>> f = lambda x: 2*x
>>> g = lambda x: x*x
>>> fg = compose(f, g)
>>> fg(2) ## f(g(2))
8
zip_with which works exactly like zip, but it also takes first argument as combiner function.
>>> zip_with(lambda x:y: x+y, [1,2,3,4], [1,1,1,1])
[2,3,4,5]
fold which reduces given list into single item using combiner function
>>> fold(lambda x,y: x+y, [1,1,1,1,1] , 0)
5
bonus
repeat such that it resturns a new function which is equivalent to a function applying n times.
>>> f = repeat(lambda x:2*x, 5)
>>> f(1)
32
def make_poly():
return lambda x: x**x + x + 1
p = make_poly()
p(3)
p(1)
def make_poly(coeffs):
def poly(x):
s = 0
for i, c in enumerate(coeffs):
s = s + c*x**i
return s
return poly
P = make_poly([1, 1, 1])
P(1)
P(2)
def make_logger(msgtype):
def logger(msg):
print(msgtype.upper(), ":", msg)
return logger
info = make_logger("info")
error = make_logger("error")
info("THis i sjust info")
error("Error message....")
def repeat(f, initial, n):
for i in range(n):
initial = f(initial)
return initial
repeat(lambda x:2*x, 1, 5)
def compose(f, g):
def fg(x):
return f(g(x))
return fg
f = lambda x: 2*x
g = lambda x: x**2
fg = compose(f, g)
fg(2)
def zip_with(f, v1, v2):
return [f(i,j) for i, j in zip(v1, v2)]
x = [1,2,3,4]
y = [1, 1, 1,1]
for i, j in zip(x, y):
print(i+j)
def zip_with(f, *args):
return [ f(*val) for val in zip(*args)]
zip_with(lambda x, y, z: x+y+z, [1,1,1,1],[2,2,2,2],[3,3,3,3])
def f(*args):
return sum(args)
zip_with(f, [1,1,1,1],[2,2,2,2],[3,3,3,3])
zip_with(f, [1,1,1,1],[2,2,2,2])
def sumof(term, n):
s = 0
for i in range(1, n+1):
s += term(i)
return s
def piseries(n):
return 8/((4*n-3)*(4*n-1))
sumof(piseries, 1000)
def fold(f, seq, initial):
s = initial
for i in seq:
s = f(s, i)
return s
import operator
fold(operator.add, range(101), 0)
sum(range(101))
def square(x):
return x*x
def debug(f):
def wrapper(*args):
print("Begin :", f.__qualname__, args)
r = f(*args)
print("Returning :", f.__qualname__,"=>", r)
return wrapper
add
def add(x, y):
return x+y
add
aliasadd = add
aliasadd
add(3, 4)
aliasadd(3, 4)
square = debug(square)
square(3)
r = square(3)
print(r)
def square(x):
return x*x
def debug(f):
def wrapper(*args):
print("Begin :", f.__qualname__, args)
r = f(*args)
print("Returning :", f.__qualname__,"=>", r)
return r
return wrapper
square = debug(square)
square(5)
@debug
def sumofsquares(x, y):
return square(x) + square(y)
sumofsquares(3, 5)
def cube(x):
"""
returns x*x*x
"""
return x**3
help(cube)
@debug
def area(radius):
"""
computes area of a circle
"""
return 3.14*radius**2
area(4)
help(area)
cube.__doc__
from functools import wraps
def debug(f):
@wraps(f)
def wrapper(*args):
print("Begin :", f.__qualname__, args)
r = f(*args)
print("Returning :", f.__qualname__,"=>", r)
return r
return wrapper
@debug
def area(radius):
"""
computes area of a circle
"""
return 3.14*radius**2
help(area)
area.__doc__
area.__annotations__
area.__qualname__
area.__doc__
area.__defaults__
def f(x=10):
pass
f.__defaults__
problems
deprecated which prints deprecation message when the function is called.with_retries which rtries the decorated function 5 times. After five tries it prints message of "Giving up!" and quits.timeit which times execution of decorated functionimport requests
!pip install requests
try:
requests.get("http://nosuchsite.sdjksjlk/lsdsa/")
except Exception as e:
print("Failed to downlod!")
import time
time.time()
def deprecated(f):
@wraps(f)
def wrapper(*args, **kwargs):
print("Function {funcname} is deprecated".format(funcname=f.__qualname__))
print("You should instead use ...foo()")
return f(*args, **kwargs)
return wrapper
@deprecated
def hello():
print("hello world!")
hello()
def with_retries(f):
@wraps(f)
def wrapper(*args, **kwargs):
for i in range(5):
try:
return f(*args, **kwargs)
except Exception as e:
print("Retrying ..", f.__qualname__, i, e)
print("Giving up!")
return wrapper
@with_retries
def wget(url):
resp = requests.get(url)
return resp.text
wget("http://nosuchlkjsdalks.ksajdkjsa/sdsd")
%%file trace.py
import os
from functools import wraps
level = 0
def log(*args):
if os.getenv("DEBUG") == "true":
print(*args)
def trace(f):
@wraps(f)
def g(*args):
global level
log("| "*level + "|--" + f.__qualname__, args )
level += 1
value = f(*args)
level -=1
log("| "*level + "|--" + "return" , value)
return value
return g
import trace
@trace.trace
def square(x):
return x*x
@trace.trace
def somofsquares(x,y):
return square(x) + square(y)
somofsquares(5, 6)
import os
%%file ssq.py
from trace import trace
import sys
@trace
def square(x):
return x*x
@trace
def sumofsquares(x,y):
return square(x) + square(y)
if __name__ == "__main__":
sumofsquares(int(sys.argv[1]), int(sys.argv[2]))
!DEBUG=true python ssq.py 5 6
%%file fib.py
import sys
from trace import trace
@trace
def fib(n):
if n in [1,2]:
return 1
else:
return fib(n-1) + fib(n-2)
if __name__ == "__main__":
print(fib(int(sys.argv[1])))
!DEBUG=true python fib.py 8
%%file memoize.py
from functools import wraps
def memoize(f):
cache = {}
@wraps(f)
def g(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return g
%%file fib1.py
import sys
from trace import trace
from memoize import memoize
@memoize
@trace
def fib(n):
if n in [1,2]:
return 1
else:
return fib(n-1) + fib(n-2)
if __name__ == "__main__":
print(fib(int(sys.argv[1])))
!DEBUG=true python fib1.py 30
os.environ['DEBUG']="true"
Write a decorator with_retries that takes two parameters , retries, delay
@debug
def foo():
pass
@with_retries(retries=5, delay=5)
def wget(url):
pass
`
def f():
pass
f
f()
from functools import wraps
def with_retries(retries=5, delay=2):
def decor(f):
@wraps(f)
def wrapper(*args, **kwargs):
for i in range(retries):
try:
return f(*args, **kwargs)
except Exception as e:
time.sleep(delay)
print("Retrying {}, attempt ".format(f.__qualname__), i+1)
return wrapper
return decor
@with_retries(retries=3, delay=2)
def wget(url):
resp = requests.get(url)
return resp.text
wget("htpp://sdsdsdsa.dasddsad.ghgfyrt/dfdf")
from functools import partial
def add(x, y, z):
return x+y+z
add2 = partial(add, x=5)
add2(y=2, z=3)
from functools import wraps
def with_retries(f = None, retries=5, delay=2):
if f==None:
return partial(with_retries, retries=retries, delay=delay)
@wraps(f)
def wrapper(*args, **kwargs):
for i in range(retries):
try:
return f(*args, **kwargs)
except Exception as e:
time.sleep(delay)
print("Retrying {}, attempt ".format(f.__qualname__), i+1)
return wrapper
@with_retries(retries=4, delay=1)
def downlod(url):
raise Exception("Can't download")
downlod()
!grep --help
%%file task.py
import math
import time
import sys
def square(x):
return x*x
def delay():
time.sleep(1)
def compute_task(n):
s = 0
for i in range(n):
s += square(i)
print(s)
s = 0
for i in range(n):
s += math.sqrt(i)
print(s)
for i in range(5):
delay()
if __name__ == "__main__":
compute_task(int(sys.argv[1]))
!python -m cProfile task.py 10000000
import task
import cProfile
cProfile.run("task.compute_task(10000)")
help(cProfile.run)
cProfile.run("task.compute_task(10000)", sort=0)
cProfile.run("task.compute_task(10000)", filename="task.prof")
!tail -n 5 task.prof