JamCoders

💾 Download

JamCoders Day 3 Lecture 1

Boaz Barak

Going deeper into functions

Ignore this section

In [1]:
def md_table(array):
    """ the same input as above """

    nl = "\n"
    t = 30

    markdown = nl
    markdown += f"| {' | '.join([x.ljust(t-2) for x in array[0]])} |"

    markdown += nl
    markdown += f"| {' | '.join(['-'*(t-2)]*len(array[0]))} |"

    markdown += nl
    for entry in array[1:]:
        L = [entry[0].ljust(t-2)] + [ f'<font color="blue"><b>{x}</b></font>'.ljust(t-2) for x in entry[1:]]
        markdown += f"| {' | '.join(L)} |{nl}"

    return markdown

from IPython.display import Markdown, display
from IPython.display import clear_output

display(Markdown(md_table([["Name","Age"],["Boaz","48"]])))
Name Age
Boaz 48
In [2]:
MARKDOWN = ""
DEBUG = True
def state(code,line,variables,depth):
    if not DEBUG: return
    lines = code.split('\n')
    lines[line] += " #<-------"     
    code = "\n".join(lines)
    global MARKDOWN
    global DEPTHS
    md_lines = MARKDOWN.split("\n")
    if depth>0:
        found = [i for i,x in enumerate(md_lines) if x[:9]=="```python" ]
        if len(found)>depth:
            md_lines = md_lines[:found[depth]]
        md = "\n".join(md_lines)+"\n"
    else:
        md = ""
    md += rf"""```python
    {code}```
    
    """
    table = [["Variable", "Value"]] + [[k,v] for k,v in variables.items()]
    md += md_table(table) +"\n\n\n"
    MARKDOWN = md
    clear_output()
    #if depth: print(found, len(md_lines))
    display(Markdown(MARKDOWN))
    if input("---"*depth+":")=="q":
        raise Exception()

def lookinto(name):
    global DEBUG
    DEBUG=True
    globals()[name] = globals()[name+"_"]
    
def normal():
    global DEBUG
    DEBUG = False
In [3]:
code_m ="""
def multiply(a,b):
    result = 0
    for i in range(b):
        result += a
    return result
"""

import inspect

def up_locals():
    frame = inspect.currentframe()
    return frame.f_back.f_back.f_locals
        
        
def multiply_(a,b,depth=0):
    def s(i): 
        state(code_m,i+1,{k:v for k,v in up_locals().items() if k!="s" and k!="depth"},depth)
    result = 0 #1
    s(1)
    for i in range(b): #2
        s(2)
        result += a #3
        s(3)
    s(4)
    return result #4
In [4]:
code_e = """
def exponent(x,y):
    result = 1
    for i in range(y):
        result = multiply(result,x)
    return result
"""

def exponent_(x,y,depth=0):
    def s(i): 
        state(code_e,i+1,{k:v for k,v in up_locals().items() if k!="s" and k!="depth"},depth)
    result = 1 #1
    s(1)
    for i in range(y): #2
        s(2)
        s(3)
        result = multiply(result,x, depth=1) #3
    s(4)
    return result #4

Calling functions example

Question: Write function multiply that takes inputs integers $a,b$ and returns $a\times b$ without using *

In [5]:
def multiply(a,b):
    ...
In [6]:
# question: multiply two integer without using *
def multiply(a,b):
    result = 0
    for i in range(b):
        result += a
    return result
In [7]:
multiply(3,5)
Out[7]:
15

Diving in

In [8]:
lookinto("multiply")
In [9]:
multiply(3,5)
def multiply(a,b):
    result = 0
    for i in range(b):
        result += a
    return result #<-------
Variable Value
a 3
b 5
result 15
i 4
:
Out[9]:
15
In [10]:
normal()

Question: Write a function exponent that takes as input two integers $x,y$ and returns $x^y$ without using * or **. It can use multiply

In [11]:
def exponent(x,y):
    ...
In [12]:
def exponent(x,y):
    result = 1
    for i in range(y):
        result = multiply(result,x)
    return result
In [13]:
exponent(2,3)
Out[13]:
8
In [14]:
lookinto("exponent")
In [15]:
exponent(2,3)
def exponent(x,y):
    result = 1
    for i in range(y):
        result = multiply(result,x)
    return result #<-------
Variable Value
x 2
y 3
result 8
i 2
:
Out[15]:
8

More function examples

In [16]:
def passing_grade(score):
    if score > 50:
        return True
    return False
print(passing_grade(60))
print(passing_grade(25))
True
False

Reminder - difference between print and return

In [17]:
def passing_grade(score): # print version
    if score > 50:
        print("True")
    print("False")
In [18]:
if passing_grade(99):
    print("That's a great grade")
True
False
In [19]:
def passing_grade(score): # print version
    if score > 50:
        return True
    return False
In [20]:
if passing_grade(99):
    print("That's a great grade")
That's a great grade

Using a function

Suppose we have the passing_grade function above. Write a function passed that takes as input two lists students and grades and prints the names of the students that passed.

In [21]:
def passed(students,grades):
    ...
In [22]:
def passed(students,grades):
    n = len(students)
    for i in range(n):
        if passing_grade(grades[i]):
            print(students[i])
In [23]:
students = [ "Bereket", "Annamira", "Elijah", "Orr", "Jabari", "Annakai", "Tyler" ]
In [24]:
# let's make grades random for fairness
import random
grades = []
for i in range(len(students)):
    grades.append(random.randint(1,100))

grades
Out[24]:
[50, 98, 27, 32, 6, 18, 49]
In [25]:
passed(students,grades)
Annamira

Functions (variable scoping)

In [26]:
# Variables inside a function have no relation to variables outside the function
# See what happens when "i" is printed inside and outside the function

i = 0
def func(x):
    i = 10
    print("i=",i, "x=",x)
    
func(5)
print("i=",i)
i= 10 x= 5
i= 0
In [27]:
# Variables across functions have no relation to each other
# A variable declared inside a function will have no relation to outside the function
# Why is there an error?

def func1(x):
    j = 10
    print("j=",j, "x=",x)

def func2(x):
    j = 5
    func1(x)
    print("x=",x)
    
func2(3)
print(j)
j= 10 x= 3
x= 3
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [27], in <cell line: 15>()
     12     print("x=",x)
     14 func2(3)
---> 15 print(j)

NameError: name 'j' is not defined
In [28]:
# Why is this the output?

k = 0
for i in range(3):
    print(k)
0
0
0
In [29]:
# How about here?

k = 0
for i in range(3):
    k = 6
    print(k)
6
6
6

Questions