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.
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.
builtins = (open,bool,chr,id)
#builtins = (open,bool,chr,enumerate)
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.
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))+1
return sum(map(lambda x: 1 if x else 0,i))
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.
def nrep(n,c):
#return [(a+1)*b for a,b in zip(n,c)]
return [a*b for a,b in zip(n,c)]
nrep([3,0,1],"abc")
['aaa', '', 'c']
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.
def stable(c):
r = abs(c)
#if r < 1.5:
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
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()
.
def onetry():
import random
if random.random() > 0.5:
print("raising ValueError")
raise ValueError
else:
raise NotImplementedError
def rerun(f,n):
while n>0:
try:
f()
except ValueError:
n -= 1
#n -= 2
except:
pass
return
rerun(onetry,5)
raising ValueError raising ValueError raising ValueError raising ValueError raising ValueError
# lab validation code; do not modify
def labcheck(testing=0,ntest=10):
'''
Python exercise checking.
Ed.Casas 2023-5-22
Calls functions q<n>* and checks HMAC of return value[0].
On mismatch prints return value[1] (e.g. function, arguments and return values).
Setting testing=1 prints HMACs of correct results; paste into 'hashvalues'.
Notes:
If q<n>* result not JSON-able, convert to string.
Result order matters for comparison. Sort result if specific order not required.
'''
import base64, copy, hashlib, json, random, re, string, types
from random import randint
# compare regex to strings that should/shouldn't match
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}'"
# list of n words with nl letters from chars without repeats
def randwords(n,chars=string.ascii_lowercase,nl=(2,5)):
l = []
while len(l)<n:
w = ''.join([chars[randint(0,len(chars)-1)] for i in range(randint(*nl))])
if w not in l:
l.append(w)
return l
# convert sets to dicts and dict keys to strings so they can be sorted
def orderkeys(o):
if isinstance(o,set):
return {str(k):None for k in o}
if isinstance(o,dict):
return {str(k):orderkeys(v) for k,v in o.items()}
return o
class newlist(list):
pop, copy = None, None
def __getitem__(self,i):
raise NotImplementedError("it's not a list!")
# Q1a, Q1b, ...
names=[]
for f in builtins:
try:
names.append(f.__name__)
except:
names.append("???")
def Q1a(): return names[0],f"builtins[0] ({names[0]}) is wrong"
def Q1b(): return names[1],f"builtins[1] ({names[1]}) is wrong"
def Q1c(): return names[2],f"builtins[2] ({names[2]}) is wrong"
def Q1d(): return names[3],f"builtins[3] ({names[3]}) is wrong"
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)
return r, 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)
return r,f"nrep({n},{c}) returns {r}"
def Q4():
r = []
for i in range(40):
c = complex(random.random(),random.random())
try:
stable(c)
except ValueError:
abs(c) <= 1 and r.append(f"stable({c:.3f}) did not raise ValueError")
continue
except Exception as e:
r.append(f"stable({c:.3f}) raised exception {e}")
continue
abs(c) > 1 and r.append(f"stable({c:.3f}) did not raise exception")
return r,'\n'.join(r)
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)
return f"{n}{m}",f"rerun(f,{n}) asserted ValueError {m} times."
hashvalues = '''
zY5pzY5pzY5pzY5pzY5pzY5pzY5pzY5pzY5pzY5p
YRUxYRUxYRUxYRUxYRUxYRUxYRUxYRUxYRUxYRUx
sjVusjVusjVusjVusjVusjVusjVusjVusjVusjVu
yT6RyT6RyT6RyT6RyT6RyT6RyT6RyT6RyT6RyT6R
+Hd6LgOnHreh6x5+LgOndp1qLgOnZEo+HrehVj+X
bVYN3Dd7w+Wq9iVBo1+Y/pjXUBBgm+F+oZytc2QJ
q1ESq1ESq1ESq1ESq1ESq1ESq1ESq1ESq1ESq1ES
2rEtmXGz2445mXGz2rEtmXGz2rEtmXGzmXGzxbQr
'''.split()
newhash = ''
dsize = 3 # HMAC base64 digest size (bytes, use 3 or 6 for 4 or 8 char digests)
dlen = ((dsize*8+5)//6+3)//4*4
for n,f in [(n,f) for n,f in locals().items() if callable(f) and re.search(r'^[Qq]\d+.*',n)]:
random.seed(n)
hashes = '0'*dlen*ntest if testing else hashvalues.pop(0)
err = ''
while hashes and not err:
h, hashes = hashes[:dlen], hashes[dlen:]
try:
v,s = f()
b = json.dumps(orderkeys(v),sort_keys=True).encode()
c = base64.b64encode(hashlib.blake2b(b,digest_size=dsize).digest()).decode()
if testing:
print(s)
newhash += c
else:
if c != h:
err = f"Wrong result for test {n}: {s} (HMAC={c} instead of {h})"
except Exception as e:
err = f"Error during test {n}: {e}"
if testing:
print(err)
if testing:
newhash += '\n'
else:
print(err or f"Passed test {n}.")
if testing:
print(newhash)
labcheck()
Passed test Q1a. Passed test Q1b. Passed test Q1c. Passed test Q1d. Passed test Q2. Passed test Q3. Passed test Q4. Passed test Q5.