Nov 20-22, 2017 Vikrant Patil
These notes will be available online at http://notes.pipal.in/2017/vmware-nov-advpython/ after this training!
© Pipal Academy LLP
We will be using following python3 distribution for this training
4 + 2.0
4 ** 1000
5 /2
5//2
"There" "are" "strings"
"string with ' quote"
'string with " quote'
multi = """
this
is a
multi line
string
"""
print(multi)
digits = list(range(10))
digits
digits[0]
digits[9]
digits[-1]
digits[-1]
digits[1:6] #starts at index 1 (inclusive) and ends at 6th(exlusive)8
digits[2:8:3]
digits[2:8] # step is 1 by default
digits[2:]
digits[:8]
digits[:]
digits[:-1] #all except last
digits[::-1] #reverse
word = "madam"
word == word[::-1]
numbers = list(range(1,10))
numbers
numbers = range(1,10)
numbers
squares = [n*n for n in numbers]
evens = [n for n in numbers if n%2==0]
evens
sentence = "This is some random statement"
words = sentence.split()
[word.upper() for word in words]
"it" is "not english"
"hell" in "hello"
person = {
"name":"Alice",
"email":"alice@wonder.land",
"roles":["Admin", "Staff"]
}
person['roles']
[key for key in person.keys()]
[v for v in person.values()]
for key, value in person.items():
print(key, value)
%%file data.csv
A1,B1,C1
A2,B2,C2
A3,B3,C3
A4,B4,C4
open("data.csv").readlines()
[line.strip().split(",") for line in open("data.csv").readlines()]
problem: Write a function quicksort which sorts given list using quicksort mechanism. in quisort mechanism you define a pivot element and filter all the elements less than pivote to left side of pivote and all the elements greater than pivote are put on right side of pivot. Then you operate quicksort recursively over filtered less and greater lists.
def morethan(items, x):
return [item for item in items if item>x]
def lessthan(items, x):
return [item for item in items if item<=x]
def quicksort(seq):
if seq:
pivot = seq[0]
tail = seq[1:]
less = lessthan(tail, pivot)
more = morethan(tail, pivot)
return quicksort(less)+ [pivot] + quicksort(more)
else:
return []
quicksort([3,1,6,2,3,6,1,9,6])
quicksort([])
quicksort([1,1,1,1])
def cylinder_volume(radius, height):
return 3.14*radius**2*height
cylinder_volume(1.0, 10) # radius = 1, height = 10
cylinder_volume(10, 1.0)# by mistake! ...results will bve wrong..will be very difficult to
#debug
cylinder_volume(radius=1,height=10)
cylinder_volume(1, height=10)
cylinder_volume(radius=1, 10)
cylinder_volume(height=10, radius=1)
def email(name, domain="vmware.com"):
return name + "@" + domain
email("shiva")
email("shiva", "intute.com")
email("shiva", domain="vmware.in")
import random
def number():
return random.random()
def func(index, randnum=number()):
print(index, randnum)
for i in range(5):
func(i)
def func(index, randnum=None):
if not randnum: #randnum==None
randnum = number()
print(index, randnum)
for i in range(5):
func(i)
def sumation(values, *, inital=50):
return inital + sum(values)
sumation(range(1,11), inital=0)
sumation(range(1,11))
sumation(range(1,11), 40)
mysum(1,2)
mysum(1,2,3,4,5)
def func(*args):
pass
func(1)
func(1,2,3)
def func(*args):
print(args)
func(1,2,3)
sum([1,2,3,4])
sum((1,2,3,4))
def mysum(*args):
return sum(args)
def mysum_(*args):
s = 0
for item in args:
s += item
return s
mysum(1,2,3,4,5)
",".join(["A","B","C"])
def joinstring(*args, sep=" "):
total = args[0]
for item in args[1:]:
total = total + sep + item
return total
joinstring("A","B","C")
joinstring("Alanzo","church","though","about","lambda","calculas")
def make_person(name, **kwargs):
person = {"name":name}
for k,v in kwargs.items():
person[k] = v
return person
make_person(name="alice",email="alice@example.com",phone="8989232983")
def f(*args,name="alice"):
print(args)
print(name)
f(1,2,3,4)
def f1(*args, x): # after *args there are named only arguments
print(args, x)
f1(1,2,3,x="name")
f1(1,2)
def find_stats(*args):
results ={
'sum':mysum(*args),
"mean":mysum(*args)/len(args),
'max':max(args),
'min':min(args)
}
return results
find_stats(1.,2.,1.1,1.2)
def timeseries(*values, **kwargs):
stats = find_stats(*values)
ploting_data = {}
ploting_data['values'] = values
ploting_data['stats'] = stats
for k,v in kwargs.items():
ploting_data[k] = v
return ploting_data
timeseries(0.01,0.012,0.011,0.013,
group="cancer",
obesrvations="raw_intensity",
experiment="gene",
gene="RC33")
timeseries([1,2,3,4],name="A",surname="B")
def f(*args, **kwargs):
print(args)
print(kwargs)
f([1,2,3,4],[1,1,1],"hello",name="name")
def func(x):
return x*x
func
type(func)
x = 3
x
func
y = x
y
square = func
square
square == func
func(3)
square(4)
def sum_natural(n):
s = 0
for i in range(1,n+1):
s += i
return s
def square(x):
return x*x
def sum_squares(n):
s = 0
for i in range(1,n+1):
s += square(i)
return s
def cube(x):
return x*x*x
def sum_cubes(n):
s = 0
for i in range(1,n+1):
s += cubes(i)
return s
def sum_func(n, f):
s = 0
for i in range(1, n+1):
s += f(i)
return s
sum_squares(10)
sum_func(10, square)
f = lambda x:x*x
f
sum_func(10, lambda x:x*x*x)
the series 8/(1*3) + 8/(5*7) + 8/(9*11) .... slowly converges to value of pi
sum_func(1000, lambda n:8/((4*n-3)*(4*n-1)))
def make_adder(x):
def adder(y):
return x+y
return adder
adder5 = make_adder(5)
adder5
adder5(4)
adder5(10)
adder7 = make_adder(7)
adder7(5)
adder5(6)
adder5("dgfgf")
def make_logger(prefix):
def logger(*args):
print(prefix, *args)
return logger
info = make_logger("[INFO]")
warn = make_logger("[WARNING]")
info("called some function", square)
warn("Something went wrong", Exception("invalid id"))
records =[
("A",40),
("B",86),
("C",48),
("D",75)
]
max(records)
def get_marks(record):
return record[1]
max(records, key=get_marks)
import os
from os.path import getsize
files = os.listdir(os.getcwd())
max(files, key=getsize)
records = [
("A",90,6.6),
("B",100, 6.7),
("C",110, 7.0),
("D",95, 10.0)
] #column 0 is name, column1 is systolic BP, column2 is sugar
def column(index):
return lambda row:row[index]
max(records, key=column(1))
max(records, key=column(2))
sentence = "Lets print longest word out of this statement"
words = sentence.split()
max(words)
max(words, key=len)
problem: Write a function compose which will take two functions f, g as arguments.
and return a function which can compute f(g(x)) given x
>>> f = lambda x:x*x
>>> g = lambda x :x-1
>>> fg = compose(f,g)
>>> fg(3)
4
>>> gf = compose(g,f)
>>> gf(3)
8
def compose(f,g):
return lambda x: f(g(x))
problem Write a function zip_with which takes function f as argument and returns a function which zips two lists into single list by combining element by element using f
>>> listadder = zip_with(lambda x,y:x+y)
>>> listaddder([1,2,3],[1,1,1])
[1,3,4]
>>> listmulti = zip_with(lambda x,y:x*y)
>>> listmulti([1,2,3],[2,2,2])
[2,4,6]
fold which reduces given sequence in to a single item given a joiner function
>>> def add(x,y):
... return x+y
>>> fold(add, [1,2,3,4,5], default=0)
15
>>> fixed_point(math.cos, 1)
0.73905479...
def list_adder(list1, list2, f):
return [f(list1[i], list2[i]) for i in range(len(list1))]
def zip_with(f):
def joiner(first, second):
z = []
for i in range(len(first)):
v = f(first[i], second[i])
z.append(v)
return z
return joiner
def add(x, y):
return x+y
def mult(x,y):
return x*y
listadder = zip_with(add)
listadder([1,1,1,1],[2,2,2,2])
def make_adder(x):
def adder(y):
return x+y
return adder
adder5 = make_adder(5)
adder5(6)
def fold(f, seq, default=0):
acc = default
for item in seq:
acc = f(acc, item)
return acc
fold(lambda x,y:x+y, [1,1,1,1,1])
fold(lambda x,y:x*y, range(1,5), default=1)
def add(x,y):
# print(x,y)
return x+y
def sub(x,y):
return x-y
def mult(x,y):
return x*y
def double(x):
return 2*x
def debug(f):
def wrapper(*args):
print(f.__qualname__, args)
v = f(*args)
print("returning ",f.__qualname__, v)
return v
return wrapper
add(3,4)
add1 = debug(add)
add1(3,4)
add = debug(add)
add(4,5)
@debug
def fib(n):
if n in [1,2]:
return 1
else:
return fib(n-1) + fib(n-2)
fib(5)
Lets build some advanced debugger which gives us complete trace of a function call
%%file trace.py
import os
level = 0
def log(*args):
if os.getenv("DEBUG")=="true":
print(*args)
def trace(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
%%file sum.py
from trace import trace
@trace
def square(x):
return x*x
@trace
def sumofsquares(x,y):
return square(x) + square(y)
if __name__ == "__main__":
print(sumofsquares(3,4))
!python sum.py
!DEBUG=true python sum.py
%%file fib.py
import sys
from trace import trace
@trace
def fib(n):
"""
computes nth fibonacci number
"""
if n in [1,2]:
return 1
else:
return fib(n-1)+fib(n-2)
def main():
n = int(sys.argv[1])
fib(n)
if __name__ == "__main__":
main()
!DEBUG=true python fib.py 5
!DEBUG=true python fib.py 8 | grep "fib (2,)" | wc -l
%%file memoize.py
def memoize(f):
cache ={}
def g(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return g
%%file sq1.py
from memoize import memoize
@memoize
def square(x):
print("Calling function square({})".format(x))
return x*x
if __name__ == "__main__":
print(square(2))
print(square(2))
!python sq1.py
%%file fib1.py
import sys
from trace import trace
from memoize import memoize
@memoize
@trace
def fib(n):
"""
computes nth fibonacci number
"""
if n in [1,2]:
return 1
else:
return fib(n-1)+fib(n-2)
def main():
n = int(sys.argv[1])
fib(n)
if __name__ == "__main__":
main()
!DEBUG=true python fib1.py 8
!time -p python fib.py 30
!time -p python fib1.py 30
%%file sq1.py
def square(x):
return x*x
def test():
print(square(3))
if __name__ == "__main__":
test()
!python sq1.py
%%file sq2.py
def square(x):
return x*x
def test():
if square(3)==9:
print("passed")
if __name__ == "__main__":
test()
!python sq2.py
%%file sq3.py
def square(x):
return x*x
def test_square():
assert square(0) == 0
assert square(-1) == 1
assert square(3) == square(-3)
assert square(3) == 9
assert square(1) == 0
if __name__ == "__main__":
test_square()
!python sq3.py
py.test is third party tool which makes use of this fact about how assert statement works and is used for automated testing
pip3 install pytest
!pytest sq3.py
%%file weekday.py
import datetime
def now():
return datetime.datetime.now()
def weekday():
t = now()
return t.strftime("%A")
if __name__ == "__main__":
print(weekday())
!python weekday.py
%%file test_weekday.py
import weekday
import datetime
def test_weekday(monkeypatch):
faketime = 2010, 1, 1
def fakenow():
return datetime.datetime(*faketime)
monkeypatch.setattr(weekday, "now", fakenow)
faketime = 2010, 1, 1
assert weekday.weekday() == "Friday"
faketime = 2010, 1, 2
assert weekday.weekday() == "Saturday"
!pytest test_weekday.py
%%file module.py
def add(x,y):
return x+y
print("hello")
!python module.py
import module
%%file backup.py
def add(x,y):
return x+y
def backup():
print("called backup")
delete(dirpath)
mkdir(newdir)
cp(src, dest)
backup()
!python backup.py
from backup import backup
%%file backup1.py
def add(x,y):
return x+y
def backup():
print("called backup")
delete(dirpath)
mkdir(newdir)
cp(src, dest)
print(__name__)
!python backup1.py
from backup1 import backup
%%file backup2.py
def add(x,y):
return x+y
def backup():
print("called backup")
delete(dirpath)
mkdir(newdir)
cp(src, dest)
if __name__ == "__main__":
backup()
if __name__ == "backup2":
print("I am a module not script")
!python backup2.py
import backup2
from backup2 import backup