ELEX 4653 Lab 3¶

This lab provides practice looking up built-in functions and using iterators and exceptions.

Version 2: compatible with Python 3.7.

Instructions:

  • Modify this notebook by adding the Python code described below.

  • Test your code using the menu item Cell ► Run All

  • Save the notebook (the .ipynb file) and upload it to the appropriate Assignment folder on the course web site.

Question 1¶

The documentation in the Built-in Functions section of the Python Standard Library documentation describes Python's built-in functions.

Define a tuple named builtins where each element is a Python function that:

  • returns an object that allows you to read from a file

  • creates an object that can only take on values True or False

  • returns a single-character string corresponding to a Unicode value

  • returns the memory address of an object (at least, in the CPython implementation of Python)

    For example, your answer might look like:

builtins = (hash,help,hex,tuple)

The entries in the tuple should be the functions, not the names of the functions as strings.

In [1]:
builtins = (open,bool,chr,id)

Question 2¶

Write a function counttrue(i) that returns the number of values returned by the iterable object i that are logically true.

For example, counttrue([True, False, '', {1}]+list(range(-3,3))) should return 7.

Note: The argument i is iterable, but it is not a list.

In [2]:
def counttrue(i):
    n=0
    for x in i:
        n += 1 if x else 0
    return n

def counttrue(i):
    return sum(map(lambda x: 1 if x else 0,i))

Question 3¶

Write a function, nrep(n,c) where n is an iterable returning integers and c is an iterable returning characters. The function should return a list of strings in which each string is the letter returned by the second iterable repeated the number of times returned by the first iterable.

For example, nrep([3,0,1],"abc") should return ['aaa', '', 'c'].

Note: n and c are iterables but not lists or strings.

In [3]:
def nrep(n,c):
    return [a*b for a,b in zip(n,c)]

nrep([3,0,1],"abc")
Out[3]:
['aaa', '', 'c']

Question 4¶

Write a function stable(c) that returns the magnitude of the complex value c if it is less than one or raises the ValueError exception otherwise.

For example if stable(0.5+0.5j) would return 0.7071... but stable(1+0.5j) would raise exception ValueError.

In [4]:
def stable(c):
    r = abs(c)
    if r < 1:
        return r
    else:
        raise ValueError
        
for s in (0, 0.5+0.5j, 1+0.5j):
    try:
        print(stable(s))
    except ValueError:
        pass
0
0.7071067811865476

Question 5¶

Write a function rerun(f,n) that repeatedly calls the function f() until f() has raised n ValueError exceptions and then returns.

Do not count the times for which no exception, or a different exception, is raised by f()

For example, if the function onetry() were defined as:

def onetry():
    import random
    if random.random() > 0.5:
        print("raising ValueError")
        raise ValueError
    else:
        raise NotImplementedError

Then rerun(onetry,5) should result in "raising ValueError" always being printed 5 times.

You do not need to define the function f() except for testing. The marking code will pass your rerun() function a different function f().

In [5]:
def onetry():
    import random
    if random.random() > 0.5:
        print("raising ValueError")
        raise ValueError
    else:
        raise NotImplementedError    

def rerun(f,n):
    while n:
        try:
            f()
        except ValueError:
            n -= 1
        except:
            pass
    return

rerun(onetry,5)
raising ValueError
raising ValueError
raising ValueError
raising ValueError
raising ValueError
In [6]:
# lab validation code; do not modify
def labcheck():
    import copy, random, re, string, types
    from random import randint
            
    def checkre(pat,ok,nok):
        for s in ok:
            assert re.fullmatch(pat,s), \
                f"pattern '{pat}'\n did not match string '{s}'"
        for s in nok:
            assert not re.fullmatch(pat,s), \
                f"pattern '{pat}'\n matched string '{s}'"  
            

    def randwords(n,chars=string.ascii_lowercase,nl=(2,5)):
        l = set()
        while len(l)<n:
            l |= set((''.join([chars[randint(0,len(chars)-1)] for i in range(randint(*nl))]),))
        return list(l)
    
    class newlist(list):
        pop, copy = None, None
        def __getitem__(self,i):
            raise NotImplementedError("it's not a list!")

    def q1():
        assert len(builtins) == 4, f"builtins has {len(builtins)} elements"
        hashvalues= (
            '5fc7e38bffe00ca46add89145464a2eaf759d5c2',
            '5039d155a71c0a5f7a2b2654ad49cb7ee47a8980',
            '52018ef6a64fdefbf8127ede4f29a9094de1c755',
            '87ea5dfc8b8e384d848979496e706390b497e547')
        import hashlib
        names=[]
        for f in builtins:
            try:
                names.append(f.__name__)
            except:
                names.append("???")
        for i,s in enumerate(names):
            h = hashlib.sha1()
            h.update(bytes(s,'utf-8'))
            # print(s,h.hexdigest())
            assert h.hexdigest() == hashvalues[i], \
                f"builtins[{i}] ({s}) is not right"

    def q2():

        l = []
        ni,ns,nw = [randint(0,3) for i in range(3)]
        nt = [ni,ns,nw]
        l.extend([1]*ni + [0]*randint(0,3))
        l.extend([{1}]*ns + [{}]*randint(0,3))
        l.extend(randwords(nw) + ['']*randint(0,3))
        random.shuffle(l)
        l = newlist(l)
        ol = copy.deepcopy(l)
        r = counttrue(l)
        assert r == sum(nt), f"counttrue({ol}) returned {r}"
    
    def q3():
        nl = randint(3,5)
        c = newlist((chr(randint(ord('a'),ord('z'))) for i in range(nl)))
        n = newlist([randint(0,4) for i in range(nl)])
        l=copy.deepcopy([n,c])
        r = nrep(*l)
        assert len(r) == nl and \
            all([((set(rs)==set(c) or not n) and len(rs)==n) for rs,n,c in zip(r,n,c)]), \
                f"nrep({n},{c}) returns {r}"
    
    def q4():
        for i in range(40):
            c = complex(random.random(),random.random())
            try:
                stable(c)
            except ValueError:
                assert c.__abs__()>1,f"stable({c:.3f}) did not raise ValueError"
                continue
            except Exception as e:
                assert False,f"stable(c) raised exception {e}"
                continue
            assert c.__abs__()<1,f"stable({c:.3f}) did not raise exception"
    
    def q5():
        n=randint(3,8)
        m=0
        def f():
            nonlocal m
            i = randint(1,3)
            if i == 1:
                m += 1
                raise ValueError
            elif i == 2:
                raise RuntimeWarning           
        rerun(f,n)
        assert m == n,f"rerun(f,{n}) asserted ValueError {m} times."
    
             
    for s,i in [(s,s[1:]) for s in locals().keys() if re.search(r'q\d+',s)]:
        try:
            locals()[s]()
            print(f"Question {i} OK.")
        except Exception as e:
            print(f"Failed check for Question {i}: {e}")
            
labcheck()
Question 1 OK.
Question 2 OK.
Question 3 OK.
Question 4 OK.
Question 5 OK.