Colab

1. write a multiply_by_10() function

create a function named ‘multiply_by_10’ that

  • receives one parameter x
  • returns x multiplied by 10
def multiply_by_10(x):
    return x*10

multiply_by_10(3)

30

2. triangles

we’re going to write function to print triangles that look like this:

   *
   **
   ***
   ****

create a function called ‘print_asterics’ that

  • receives one parameter called n
  • prints to screen one line with n asterics
>>> print_asterics(4)
****
>>> print_asterics(8)
********

use this function and a for loop to print a triangle having 10 lines


def print_asterics(n):
    line = '*' * n
    print(line)
    
for i in range(10):
    print_asterics(i+1)


*
**
***
****
*****
******
*******
********
*********
**********

3. write print_char() function

create a new function called print_char that works similarly to print_asterics,

  • except it receives the character to print as an additional parameter called ‘c’
  • the param c should have a default value of ‘*’
>>> print_char(4)
****
>>> print_char(8, '@')
@@@@@@@@ 

use this function to create this triangle with a loop

@
@@
@@@
@@@@

def print_char(n, c='*'):
    line = c * n
    print(line)
    
for i in range(5):
    print_char(i+1, '@')

@
@@
@@@
@@@@
@@@@@

4. function print_trian()

create a function print_trian to print triangles like in #3 it should receive two parameters:

  • n determines how many lines the triangle would have
  • c determines the character to use, with ‘*’ as default
>>> print_trian(5, '$')
$
$$
$$$
$$$$
$$$$$
  • hint: this function should use print_char internally
def print_trian(n, c='*'):
    for i in range(n):
        print_char(i+1, c)
        
print_trian(5, '$')

$
$$
$$$
$$$$
$$$$$

4.b write get_trian() function with return value

create a new function called get_trian, that is very similar to print_trian from #4, but instead of printing the triangle it returns the triangle as a string

>>> x = get_trian(5, '$')
>>> print(x)
$
$$
$$$
$$$$
$$$$$
def get_trian(n, c='*'):
    result = []
    for i in range(n):
        line = c * (i+1)
        result.append(line)
    
    return "\n".join(result)

x = get_trian(5, '@')
print(x)

@
@@
@@@
@@@@
@@@@@
# w

my_abs(x) function

in this exercise we’re going to implement a funtion that calculates the absolute value (ערך מוחלט) of a parameter x and we’re going to do it in 3 styles.

   x = my_abs(-10)
   print(x) # prints 10
   y = my_abs(12)
   print(y) # prints 12
  1. write a function called my_abs(x) that calculates the absolute value (ערך מוחלט) of a parameter x
def my_abs(x):
  if x<0:
    return -x
  else:
    return x

### useful: this tests your function
assert my_abs(0) == 0
assert my_abs(-10) == 10
assert my_abs(15) == 15


  1. write a function called my_abs2(x) that does the same calculation as my_abs(x)
    BUT use the single line if variant: exprssion1 if condition else expression2
def my_abs2(x):
  return -x if x<0 else x

my_abs2(-10)

10
  1. implement absolute value function using lambda syntax, put the result in a variable called my_abs3
my_abs3 = lambda x: -x if x<0 else x

my_abs3(-10)

10

calculate VAT “מס ערך מוסף”

a) write a function called calc_vat that takes a price and the VAT and calculates how much the price is after VAT

for instance:

>>> calc_vat(100, 17)
117

b) make the vat a default parameter with value 17

>>> calc_vat(100)
117

>>> calc_vat(100, 15)
115
def calc_vat(price, vat=17):
    return price * (1 + vat/100.0)

### important: test your function
assert calc_vat(100, 17) == 117
assert calc_vat(200, 20) == 240
assert calc_vat(100) == 117

zip-ing two lists together

  1. create a list of fruits, put it in a variable called fruits.

    example: ['apple', 'guava', 'pineapple', 'pear', 'peach']

  2. create a list of prices for these fruits. it should have the same length as your list of fruits. put it in a variable called prices.

    example: [10, 12, 20, 5, 8]

  3. use the zip function (look it up on google) to create a list of fruit/price pairs.

    it could look like this: [('apple', 10), ('guava', 12), ('pineapple', 20), ('pear', 5), ('peach', 8)] ```

fruits = ['apple', 'guava', 'pineapple', 'pear', 'peach']
fruits_prices = [10, 12, 20, 5, 8]
menu = dict(zip(fruits, fruits_prices))

def double_price(menu):
    return { name: price*2 for name, price in menu.items() }

print(double_price(menu))

{'apple': 20, 'guava': 24, 'pineapple': 40, 'pear': 10, 'peach': 16}

make_matrix() function

write a function called make_matrix(nrows=10, ncols=10) that returns a multiplication matrix (לוח כפל) with nrows rows and ncols rows.

the function will return a list of lists that have the following property:

make_matrix()[i][j] == i*j

for example:

>>> from pprint import pprint
>>> x = make_matrix(5, 5)
>>> pprint(x)
[[0, 0, 0, 0, 0],
 [0, 1, 2, 3, 4],
 [0, 2, 4, 6, 8],
 [0, 3, 6, 9, 12],
 [0, 4, 8, 12, 16]]
from pprint import pprint
def make_matrix(nrows=10, ncols=10):
    matrix = []
    for i in range(nrows):
        row = []
        matrix.append(row)
        for j in range(ncols):
            row.append(i*j)
        
    return matrix

x = make_matrix(5,5)
pprint(x)

[[0, 0, 0, 0, 0],
 [0, 1, 2, 3, 4],
 [0, 2, 4, 6, 8],
 [0, 3, 6, 9, 12],
 [0, 4, 8, 12, 16]]

write maxitem() function

create a function called maxitem that finds and returns the maximum item in a list

>>> maxitem([1,2,3,4,3,1])
4
def maxitem(lst):
    themax = lst[0]
    for x in lst[1:]:
        if x > themax:
            themax = x
    return themax

maxitem([1,2,3,4,3,1])

4

sort_lists() - difficult

create a function called sort_lists that can sort a list of lists. [find hints on how to do it below.]

it will work in the following way:

  • we will sort lists according to which one has the maxmium item (like in #5)
  • example:
    >>> sort_lists([
     [1,2,3],
     [2,3,4],
     [1,1,1],
     [2]
     ])
    [
    [1,1,1],
    [2],
    [1,2,3],
    [2,3,4
    ]
    
  • hint: use the function maxitem from #5 and the existing function sorted
def sort_lists(lst):
    return sorted(lst, key=maxitem)

sort_lists([
         [1,2,3],
         [2,3,4],
         [1,1,1],
         [2]
        ])

[[1, 1, 1], [2], [1, 2, 3], [2, 3, 4]]

make_add_x - difficult

create a function called make_add_x() that receives one parameter x and returns an inner function … this inner function will receive one parameter y and return x+y

>>> add7 = make_add_x(7)
>>> add7(3)
10
>>> add7(5)
12
>>> add10 = make_add_x(10)
>>> add10(100)
110

def make_add_x(x):
    def add_x(y):
        return x+y
    return add_x

add7 = make_add_x(7)
print(add7(3)) # 10
print(add7(5)) # 12

add10 = make_add_x(10)
print(add10(100)) # 110

10
12
110

myprint() - challenging

create a function called myprint that has similar properties to the built-in print() function:

  • it is variadic: it can support 0,1,2,3 or more parameters (unlimited number)
  • it supports the file, sep and end arguments

it differrs from print by prefering the character @

>>> myprint(1, 2, 3)
1 @ 2 @ 3 @
>>> myprint( [1, 2, 3], [4, 5, 6] )
[1, 2, 3] @ [4, 5, 6] @

>>> myprint(1, 2, 3, file=sys.stdout, sep=' ', end='\n')
1 2 3


import sys
def myprint(*args, sep=' @ ', end=' @\n', file=sys.stdout):
    return print(*args, sep=sep, end=end, file=file)

myprint(1, 2, 3)                #     1 @ 2 @ 3 @
myprint( [1, 2, 3], [4, 5, 6] ) #    [1, 2, 3] @ [4, 5, 6] @
myprint(1, 2, 3, file=sys.stdout, sep=' ', end='\n') # 1 2 3

1 @ 2 @ 3 @
[1, 2, 3] @ [4, 5, 6] @
1 2 3

make_debuggable() - very difficult

create a function called make_debuggable(func) that:

  • receives one paramter called func
  • returns a new function that does the same thing as func,

and can accept any argument that func accepts.

  • but in addition the returned function also helps debugging by printing out the parameters it received, and the return value it is about to return

hints:

  • use a nested function that accepts variadic positional and keyword arguments
def make_debuggable(func):
    def __get_signature(func, args, kwargs):
        fullargs = [str(a) for a in args] + [ f"{k}={v}" for k,v in kwargs.items()]
        return "{}({})".format(func.__name__, ', '.join(fullargs))
        
    def nested(*args, **kwargs):
        print(f"calling {__get_signature(func, args, kwargs)}")
        
        v = func(*args, **kwargs)
        
        print(f"{__get_signature(func, args, kwargs)} -->> {v}")
        return v
    
    return nested

import math
debug_sqrt = make_debuggable(math.sqrt)
debug_sqrt(100)
#debug_sqrt(-100)

print()

debug_print = make_debuggable(print)
debug_print(1,2,3, sep = ' @@@ ')


calling sqrt(100)
sqrt(100) -->> 10.0

calling print(1, 2, 3, sep= @@@ )
1 @@@ 2 @@@ 3
print(1, 2, 3, sep= @@@ ) -->> None