Module 2 - Day 1

Understanding function arguments

def foo(arg1, arg2, arg3):
    """arg1 , arg2, arg3 these are separate three arguments
    """
    print(arg1, arg2, arg3)
foo(1, 2, 3)
1 2 3
foo([1, 2, 3]) # we have passed list here .. that goes as single argument
TypeError: foo() missing 2 required positional arguments: 'arg2' and 'arg3'
23, 25, 2, 45, 56, 67, 89


def min2(a, b):
    if a < b:
        return a
    else:
        return b
        

def min3(x, y, z):
    return min2(min2(x, y), z)



def minimum3(a, b, c):
    if a < b and a < c:
        return a
    elif b < a and b < c:
        return b
    else:
        return c
    
min3(2, 1, 5)
1
minimum3(2, 1, 5)
1
def foo(arg1, arg2, arg3):
    """arg1 , arg2, arg3 these are separate three arguments
    this is second line of help!
    """
    print(arg1, arg2, arg3)
help(foo)
Help on function foo in module __main__:

foo(arg1, arg2, arg3)
    arg1 , arg2, arg3 these are separate three arguments
    this is second line of help!

recap for loop

for i in range(5):
    print(i, end=",")
0,1,2,3,4,
for c in "text data":
    print(c, end=",")
t,e,x,t, ,d,a,t,a,
d = {"a":1, "b":2, "c":3}

for key in d:
    print(key, d[key])
a 1
b 2
c 3

Iteration patterns

for i in reversed(range(5)):
    print(i)
4
3
2
1
0
words = ["one", "two", "three", "four", "five"]
for w in words:
    print(w, end=" ")
one two three four five 
for w in reversed(words):
    print(w, end=" ")
five four three two one 
poem = """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."""
poem
'Beautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.'
poem.split() # words
['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.']
poem.split("\n") # lines
['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.']
lines = poem.split("\n")
for line in reversed(lines):
    print(line)
Readability counts.
Sparse is better than dense.
Flat is better than nested.
Complex is better than complicated.
Simple is better than complex.
Explicit is better than implicit.
Beautiful is better than ugly.
#words.reverse() # this will reverse the list in place, but we loose original data
classroom = ["ankit", "rohit", "tejeswar", "simaran", "ansh"]
index = 0
for student in classroom:
    print(student, index)
    index = index + 1
ankit 0
rohit 1
tejeswar 2
simaran 3
ansh 4
for i, student in enumerate(classroom):
    print(i, student)
0 ankit
1 rohit
2 tejeswar
3 simaran
4 ansh
for linenum, line in enumerate(lines):
    print(linenum, line)
0 Beautiful is better than ugly.
1 Explicit is better than implicit.
2 Simple is better than complex.
3 Complex is better than complicated.
4 Flat is better than nested.
5 Sparse is better than dense.
6 Readability counts.
for linenum, line in enumerate(lines, start=1):
    print(linenum, line)
1 Beautiful is better than ugly.
2 Explicit is better than implicit.
3 Simple is better than complex.
4 Complex is better than complicated.
5 Flat is better than nested.
6 Sparse is better than dense.
7 Readability counts.
firstnames = ["Alice", "Elsa", "Alex", "Elisa"]
lastnames = ["Wondergirl", "Frozen", "Lion", "Hacker"]

for name, surname in zip(firstnames, lastnames):
    print(name, surname)
Alice Wondergirl
Elsa Frozen
Alex Lion
Elisa Hacker
words
['one', 'two', 'three', 'four', 'five']
nums = [1, 2, 3, 4, 5]
for n, w in zip(nums, words):
    print(n, w)
1 one
2 two
3 three
4 four
5 five
length = len(words)
for i in range(length):
    print(nums[i], words[i]) # indexing is bad idea
1 one
2 two
3 three
4 four
5 five
for n, w in zip(nums, words):
    print(n, w)
1 one
2 two
3 three
4 four
5 five

What if one of the list is shorter in lenght?

In that case assosiation done by zip is for a shorter list (collection). It will ignore remaining items from bigger list/collection

classroom
['ankit', 'rohit', 'tejeswar', 'simaran', 'ansh']
rollnums = [1, 2, 3, 4]
for r, s in zip(rollnums, classroom):
    print(r, s) # it will
1 ankit
2 rohit
3 tejeswar
4 simaran
xs = ['x1', 'x2', 'x3', 'x4'] # list of some strings
ys = ['y1', 'y2', 'y3', 'y4'] #
zs = ['z1', 'z2', 'z3', 'z4']
for x, y, z in zip(xs, ys, zs):
    print(x, y, z)
x1 y1 z1
x2 y2 z2
x3 y3 z3
x4 y4 z4

Few things to remember while using iterators

Iterators are for one time consumtion

nums = [1, 2, 3, 4, 5]
rnums = reversed(nums)
print(rnums)
<list_reverseiterator object at 0x7fdd74191630>
for i in rnums: # with for loop we consume the iterator
    print(i)
5
4
3
2
1
for i in rnums: # iterator is alreade consumed!
    print(i)
for item in []:
    print(item)
for i in reversed(nums): # every time I execute this line reversed iterator is created fresh and used
    print(i)
5
4
3
2
1

Never store these iterators in a variable and then use it later, it will create a confusion whether the iterator is already consumed or not!

for i in reversed(nums): # every time I execute this line reversed iterator is created fresh and used
    print(i, end=" ") # end the print with space instade of new line
5 4 3 2 1 
for i in reversed(nums): 
    print(i, end=",") 
5,4,3,2,1,
print(5)
5
print(5, end=",") # 
5,
for i in reversed(nums): 
    if i == 4:
        e = "\n"
    else:
        e = ","
        
    print(i, end=e)
5,4
3,2,1,

Problem

Write a function vector_add which does vector addition of two vectors taken as a list

>>> a = [1, 1, 1, 1]
>>> b = [1, 2, 3, 4]
>>> vector_add(a, b)
[2, 3, 4, 5]

shuddhatma

def vector_add(a,b):
    for i,j in zip(a,b):
        k=[]
        k.append(i+j)
    return k
        

a=[1,2,3,4]
b=[1,2,3,4]
s = vector_add(a,b)
print(s)

rishi

def vector_add(c,d):
    s=[]
    e=c[0]+d[0]
    f=c[1]+d[1]
    g=c[2]+d[2]
    h=c[3]+d[3]
    i=s.append(e,f,g,h)
    return(i)


def vector_add(c,d):
    """This function will work for vectors of size 4 only!
    """
    s=[]
    e=c[0]+d[0]
    f=c[1]+d[1]
    g=c[2]+d[2]
    h=c[3]+d[3]
    s.append(e)
    s.append(f)
    s.append(g)
    s.append(h)
    return s
a = [1, 1, 1, 2, 2, 2]
b = [1, 2, 3, 4, 5, 6]


for i in a:
    print(i, end=",")
1,1,1,2,2,2,
for i in b:
    print(i, end=",")
1,2,3,4,5,6,
for i, j in zip(a, b):
    print(i, j)
1 1
1 2
1 3
2 4
2 5
2 6
def vector_add(a, b):
    c = []
    for x,y in zip(a,b):
        c.append(x+y)
    return c
vector_add(a, b)
[2, 3, 4, 6, 7, 8]
def vector_add(a, b):
    c = []
    for x,y in zip(a,b):
        r = x+y
        c.append(r) # append is just appending one more element at the end of list c
    return c
def vector_add (list1, list2):
    list3=[]
    
    for n, m in zip(list1, list2):
        list3.append(n+m)
        
    return list3
d1 = {"a":1,"b":2, "c":3}
d2 = {"x":5, "y":6, "z":7}

for k1, k2 in zip(d1, d2): # zip on dictionaries will take only keys
    print(k1, k2)
a x
b y
c z
words
['one', 'two', 'three', 'four', 'five']
nums
[1, 2, 3, 4, 5]
for w, n in zip(words, nums):
    print(w, n)
one 1
two 2
three 3
four 4
five 5
dict(zip(words, nums)) # this will work only with zip of two lists!
{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}
c = zip(a, b)
print(c)
<zip object at 0x7fdd74292200>
x = list(c)
x
[(1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (2, 6)]

List comprehensions

def findlens(words):
    lens = []
    for word in words:
        l = len(word)
        lens.append(l)

    return lens
findlens(words)
[3, 3, 5, 4, 4]
findlens(["dsdasa", "sadsa", "sad", "ewr", "dsf", "saasdfds"])
[6, 5, 3, 3, 3, 8]
def squares(nums):
    sqr = []
    for n in nums:
        sqr.append(n**2)

    return sqr
squares(nums)
[1, 4, 9, 16, 25]
nums
[1, 2, 3, 4, 5]
import datetime
def daterange(n):
    """generates next n dates starting from today
    """
    dates = []
    start = datetime.datetime.today() # this gives today's date
    for i in range(n):
        nextdate = start + datetime.timedelta(days=i)
        dates.append(nextdate)

    return dates
daterange(5)
[datetime.datetime(2024, 2, 14, 6, 52, 13, 711948),
 datetime.datetime(2024, 2, 15, 6, 52, 13, 711948),
 datetime.datetime(2024, 2, 16, 6, 52, 13, 711948),
 datetime.datetime(2024, 2, 17, 6, 52, 13, 711948),
 datetime.datetime(2024, 2, 18, 6, 52, 13, 711948)]
empty = []
for i in somelist:
    d = do_something(i)
    empty.append(d)

This can be converted to this kind of list comprehension

[do_something(i) for i in somelist] # this is called as list comprehension
def findlens(words):
    lens = []
    for word in words:
        l = len(word)
        lens.append(l)

    return lens


def findlens(words):
    return [len(word) for word in words]
findlens(words)
[3, 3, 5, 4, 4]
def squares(nums):
    sqr = []
    for n in nums:
        sqr.append(n**2)

    return sqr

def squares(nums):
    return [n**2 for n in nums]
squares([23, 432, 1, 23, 43, -2])
[529, 186624, 1, 529, 1849, 4]
def daterange(n):
    """generates next n dates starting from today
    """
    dates = []
    start = datetime.datetime.today() # this gives today's date
    for i in range(n):
        nextdate = start + datetime.timedelta(days=i)
        dates.append(nextdate)

    return dates

def next_date(start, i):
    return start + datetime.timedelta(days=i)

def daterange(n):
    start = datetime.datetime.today()
    return [next_date(start, i) for i in range(n)]
daterange(3)
[datetime.datetime(2024, 2, 14, 7, 0, 28, 492433),
 datetime.datetime(2024, 2, 15, 7, 0, 28, 492433),
 datetime.datetime(2024, 2, 16, 7, 0, 28, 492433)]
def even(n):
    return n%2==0
    
def square_evens(nums):
    sqrs = []
    for n in nums:
        if even(n):
            sqrs.append(n**2)
    return sqrs
square_evens([1, 2, 3, 4, 5, 6, 7, 8])
[4, 16, 36, 64]
def square_evens(nums):
    return [n**2 for n in nums if even(n)]
square_evens([1, 2, 3, 4, 5, 6, 7, 8, 9])
[4, 16, 36, 64]

problem

Write above vector_add function by using list comprehension

def vector_add(a, b):
    c = []
    for x,y in zip(a,b):
        r = x+y
        c.append(r) # append is just appending one more element at the end of list c
    return c
def vector_add(a, b):
    return [x+y for x,y in zip(a,b)]
a
[1, 1, 1, 2, 2, 2]
b
[1, 2, 3, 4, 5, 6]
vector_add(a,b)
[2, 3, 4, 6, 7, 8]

problem

Find sum of all even numbers less than 100

e = [i for i in range(100) if even(i)]
sum(e)
2450
sum([i for i in range(100) if even(i)])
2450

problem

find sum of all multiples of 7 or 11 below 1000

def cond(n):
    return n%7==0 or n%11==0
    
sum([i for i in range(1000) if cond(i)])
110110

Lets look at slightly complicated problem. Consider prices of stocks given in following format. WE want to find all items for given symbol lets say "IBM"

  indexdata = [('IBM', 'Monday', 111.71436961893693),
            ('IBM', 'Tuesday', 141.21220022208635),
            ('IBM', 'Wednesday', 112.40571010053796),
            ('IBM', 'Thursday', 137.54133351926248),
            ('IBM', 'Friday', 140.25154281801224),
            ('MICROSOFT', 'Monday', 235.0403622499107),
            ('MICROSOFT', 'Tuesday', 225.0206535036475),
            ('MICROSOFT', 'Wednesday', 216.10342426936444),
            ('MICROSOFT', 'Thursday', 200.38038844494193),
            ('MICROSOFT', 'Friday', 235.80850482793264),
            ('APPLE', 'Monday', 321.49182055844256),
            ('APPLE', 'Tuesday', 340.63612771662815),
            ('APPLE', 'Wednesday', 303.9065277507285),
            ('APPLE', 'Thursday', 338.1350605764038),
            ('APPLE', 'Friday', 318.3912296144338)]
  indexdata = [('IBM', 'Monday', 111.71436961893693),
            ('IBM', 'Tuesday', 141.21220022208635),
            ('IBM', 'Wednesday', 112.40571010053796),
            ('IBM', 'Thursday', 137.54133351926248),
            ('IBM', 'Friday', 140.25154281801224),
            ('MICROSOFT', 'Monday', 235.0403622499107),
            ('MICROSOFT', 'Tuesday', 225.0206535036475),
            ('MICROSOFT', 'Wednesday', 216.10342426936444),
            ('MICROSOFT', 'Thursday', 200.38038844494193),
            ('MICROSOFT', 'Friday', 235.80850482793264),
            ('APPLE', 'Monday', 321.49182055844256),
            ('APPLE', 'Tuesday', 340.63612771662815),
            ('APPLE', 'Wednesday', 303.9065277507285),
            ('APPLE', 'Thursday', 338.1350605764038),
            ('APPLE', 'Friday', 318.3912296144338)]
[item for item in indexdata if item[0]=='IBM']
[('IBM', 'Monday', 111.71436961893693),
 ('IBM', 'Tuesday', 141.21220022208635),
 ('IBM', 'Wednesday', 112.40571010053796),
 ('IBM', 'Thursday', 137.54133351926248),
 ('IBM', 'Friday', 140.25154281801224)]
two_vars  = (3, 5)
a, b = two_vars
words
['one', 'two', 'three', 'four', 'five']
nums
[1, 2, 3, 4, 5]
for word, number in zip(words, nums):
    print(word, number)
one 1
two 2
three 3
four 4
five 5
for x, y in zip(words, nums):
    print(x, y)
one 1
two 2
three 3
four 4
five 5
for item in zip(words, nums):
    print(item[0], item[1])
one 1
two 2
three 3
four 4
five 5
[price for  symbol, day, price in indexdata]
[111.71436961893693,
 141.21220022208635,
 112.40571010053796,
 137.54133351926248,
 140.25154281801224,
 235.0403622499107,
 225.0206535036475,
 216.10342426936444,
 200.38038844494193,
 235.80850482793264,
 321.49182055844256,
 340.63612771662815,
 303.9065277507285,
 338.1350605764038,
 318.3912296144338]
[price for  symbol, day, price in indexdata if symbol=='IBM']
[111.71436961893693,
 141.21220022208635,
 112.40571010053796,
 137.54133351926248,
 140.25154281801224]
def prices(name, indexdata):
    return [price for symbol, day, price in indexdata if symbol==name]
def mean(nums):
    return sum(nums)/len(nums)
def weekly_average(name, indexdata):
    p  = prices(name, indexdata)
    return mean(p)
weekly_average("APPLE", indexdata)
324.51215324332736

problems

  • Write a function factors which finds all factors of given number (include 1 and self)
  • write a function is_prime which tells if given number is prime or not
  • Write a list comprehension to generate prime numbers less than 100
sum([n for n in range(1000) if n%7==0 or n%11==0])
110110
list(range(5))
[0, 1, 2, 3, 4]
list(range(1, 6))
[1, 2, 3, 4, 5]
def factors():
    pass