0% found this document useful (0 votes)
12 views

61a Mt2 Study Guide

Uploaded by

lrcrwolrerine
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

61a Mt2 Study Guide

Uploaded by

lrcrwolrerine
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 2

CS 61A Midterm 2 Study Guide — Page 1

Rational implementation using functions: List comprehensions: List & dictionary mutation:

def rational(n, d): [<map exp> for <name> in <iter exp> if <filter exp>] >>> a = [10] >>> a = [10]
>>> b = a >>> b = [10]
def select(name): This Short version: [<map exp> for <name> in <iter exp>] >>> a == b >>> a == b
if name == 'n': function True True
A combined expression that evaluates to a list using this
return n represents
evaluation procedure:
>>> a.append(20) >>> b.append(20)
elif name == 'd': a rational 1. Add a new frame with the current frame as its parent
>>> a == b >>> a
number True [10]
return d 2. Create an empty result list that is the value of the >>> a >>> b
return select expression [10, 20] [10, 20]
def numer(x): 3. For each element in the iterable value of <iter exp>: >>> b >>> a == b
return x('n') Constructor is a A. Bind <name> to that element in the new frame from step 1 [10, 20] False
higher-order function B. If <filter exp> evaluates to a true value, then add
def denom(x): the value of <map exp> to the result list >>> nums = {'I': 1.0, 'V': 5, 'X': 10}
return x('d') Selector calls x >>> nums['X']
The result of calling repr on a value is >>> 12e12
10
Lists: what Python prints in an interactive session 12000000000000.0
>>> print(repr(12e12))
>>> nums['I'] = 1
>>> digits = [1, 8, 2, 8] The result of calling str on a value is 12000000000000.0 >>> nums['L'] = 50
>>> len(digits) what Python prints using the print function >>> nums
4 {'X': 10, 'L': 50, 'V': 5, 'I': 1}
digits >>> today = datetime.date(2019, 10, 13) >>> print(today)
>>> digits[3] >>> sum(nums.values())
2019-10-13
8 66
str and repr are both polymorphic; they apply to any object >>> dict([(3, 9), (4, 16), (5, 25)])
>>> [2, 7] + digits * 2 repr invokes a zero-argument method __repr__ on its argument {3: 9, 4: 16, 5: 25}
[2, 7, 1, 8, 2, 8, 1, 8, 2, 8]
>>> today.__repr__() >>> today.__str__() >>> nums.get('A', 0)
>>> pairs = [[10, 20], [30, 40]] 'datetime.date(2019, 10, 13)' '2019-10-13' 0
>>> pairs[1] >>> nums.get('V', 0)
[30, 40] pairs Type dispatching: Look up a cross-type implementation of an 5
>>> pairs[1][0] operation based on the types of its arguments >>> {x: x*x for x in range(3,6)}
30 Type coercion: Look up a function for converting one type to {3: 9, 4: 16, 5: 25}
another, then apply a type-specific implementation.
Executing a for statement:
for <name> in <expression>: Functions that aggregate iterable arguments >>> sum([1, 2]) >>> any([False, True])
<suite> • sum(iterable[, start]) -> value sum of all values 3 True
1. Evaluate the header <expression>, • max(iterable[, key=func]) -> value largest value >>> sum([1, 2], 3) >>> any([])
which must yield an iterable value max(a, b, c, ...[, key=func]) -> value 6 False
(a list, tuple, iterator, etc.) min(iterable[, key=func]) -> value smallest value >>> sum([]) >>> max(1, 2)
min(a, b, c, ...[, key=func]) -> value 0 2
2. For each element in that sequence,
>>> all([False, True]) >>> max([1, 2])
in order: • all(iterable)-> bool whether all are true False 2
A. Bind <name> to that element in any(iterable) -> bool whether any is true >>> all([]) >>> max([1, -2], key=abs)
the current frame
True -2
B. Execute the <suite> Many built-in map(func, iterable):
Unpacking in a Python sequence Iterate over func(x) for x in iterable
A sequence of operations
for statement: fixed-length sequences filter(func, iterable): You can copy a list by calling the list
return Iterate over x in iterable if func(x) constructor or slicing the list from the
iterators that beginning to the end.
>>> pairs=[[1, 2], [2, 2], [3, 2], [4, 4]] zip(first_iter, second_iter):
compute results
>>> same_count = 0 Iterate over co-indexed (x, y) pairs
lazily
reversed(sequence): >>> suits = ['coin', 'string', 'myriad']
A name for each element in a
fixed-length sequence Iterate over x in a sequence in reverse order >>> suits.pop() Remove and return
'myriad' the last element
To view the list(iterable): >>> suits.remove('string')
>>> for x, y in pairs: Remove a value
contents of Create a list containing all x in iterable >>> suits.append('cup')
... if x == y:
an iterator, tuple(iterable): >>> suits.extend(['sword', 'club'])
... same_count = same_count + 1
place the >>> suits[2] = 'spade'
>>> same_count Create a tuple containing all x in iterable Add all
resulting >>> suits
2 sorted(iterable): values
elements into ['coin', 'cup', 'spade', 'club']
a container Create a sorted list containing x in iterable Replace a
..., -3, -2, -1, 0, 1, 2, 3, 4, ... >>> suits[0:2] = ['diamond']
slice with
n: 0, 1, 2, 3, 4, 5, 6, 7, 8, >>> suits values
def cascade(n): >>> cascade(123) fib(n): 0, 1, 1, 2, 3, 5, 8, 13, 21, ['diamond', 'spade', 'club']
if n < 10: 123 Add an element
12 def fib(n): >>> suits.insert(0, 'heart')
print(n) at an index
range(-2, 2) else: 1
if n == 0: >>> suits
return 0 ['heart', 'diamond', 'spade', 'club']
print(n) 12 elif n == 1:
Length: ending value - starting value 123 return 1
cascade(n//10)
Element selection: starting value + index print(n) else:
return fib(n-2) + fib(n-1) False values: >>> bool(0)
>>> list(range(-2, 2)) List constructor •Zero False
[-2, -1, 0, 1] •False >>> bool(1)
•None True
>>> list(range(4)) Range with a 0 •An empty string, >>> bool('')
[0, 1, 2, 3] starting value >>> withdraw = make_withdraw(100) list, dict, tuple False
>>> withdraw(25) >>> bool('0')
Membership: Slicing: 75 True
All other values
>>> digits = [1, 8, 2, 8] >>> digits[0:2] The parent >>> withdraw(25) are true values. >>> bool([])
>>> 2 in digits [1, 8] 50 False
frame contains
True >>> digits[1:] def make_withdraw(balance): >>> bool([[]])
the balance of
>>> 1828 not in digits [8, 2, 8] def withdraw(amount): True
withdraw
True Slicing creates a new object nonlocal balance >>> bool({})
if amount > balance: False
Identity: >>> bool(())
return 'No funds'
<exp0> is <exp1> Every call False
balance = balance - amount
evaluates to True if both <exp0> and decreases the >>> bool(lambda x: 0)
return balance
<exp1> evaluate to the same object same balance True
return withdraw
Equality:
<exp0> == <exp1> Status x = 2 Effect
evaluates to True if both <exp0> and •No nonlocal statement Create a new binding from name "x" to number 2
<exp1> evaluate to equal values •"x" is not bound locally in the first frame of the current environment
Identical objects are always equal values
>>> s = [3, 4, 5] >>> d = {'one': 1, 'two': 2, 'three': 3}
•No nonlocal statement Re-bind name "x" to object 2 in the first frame
iter(iterable): •"x" is bound locally of the current environment
Return an iterator >>> t = iter(s) >>> k = iter(d) >>> v = iter(d.values())
over the elements of >>> next(t) >>> next(k) >>> next(v) •nonlocal x Re-bind "x" to 2 in the first non-local frame of
an iterable value 3 'one' 1 •"x" is bound in a the current environment in which "x" is bound
next(iterator): >>> next(t) >>> next(k) >>> next(v) non-local frame
Return the next element 4 'two' 2
•nonlocal x
A generator function is a function that yields values instead of returning them. •"x" is not bound in SyntaxError: no binding for nonlocal 'x' found
>>> def plus_minus(x): >>> t = plus_minus(3) def a_then_b(a, b): a non-local frame
... yield x >>> next(t) yield from a •nonlocal x
... yield -x 3 yield from b •"x" is bound in a SyntaxError: name 'x' is parameter and nonlocal
>>> next(t) >>> list(a_then_b([3, 4], [5, 6])) non-local frame
-3 [3, 4, 5, 6]
•"x" also bound locally
CS 61A Midterm 2 Study Guide — Page 2
Root or Root Node Python object system:
Recursive description: Path Nodes
Idea: All bank accounts have a balance and an account holder;
•A tree has a root label Root label 3
and a list of branches Labels the Account class should add those attributes to each of its instances
Branch
•Each branch is a tree A new instance is >>> a = Account('Jim')
•A tree with zero branches created by calling a >>> a.holder
is called a leaf 1 2 class 'Jim'
Relative description: >>> a.balance An account instance
•Each location is a node 0 1 1 1 0
When a class is called: balance: 0 holder: 'Jim'
•Each node has a label 1.A new instance of that class is created:
•One node can be the Leaf
0 1 2.The __init__ method of the class is called with the new object as its first
parent/child of another argument (named self), along with any additional arguments provided in the
def tree(label, branches=[]): call expression.
for branch in branches: Verifies the class Account:
tree definition def __init__(self, account_holder):
assert is_tree(branch)
__init__ is called a self.balance = 0
return [label] + list(branches)
constructor self.holder = account_holder
def label(tree): def deposit(self, amount):
Creates a list from a
return tree[0] self.balance = self.balance + amount
sequence of branches
return self.balance
def branches(tree): 3 self should always be
Verifies that tree is def withdraw(self, amount):
return tree[1:] bound to an instance of
bound to a list if amount > self.balance:
the Account class or a
def is_tree(tree): return 'Insufficient funds'
subclass of Account
if type(tree) != list or len(tree) < 1: 1 2 self.balance = self.balance - amount
return self.balance
return False
for branch in branches(tree): 1 1 >>> type(Account.deposit)
if not is_tree(branch): >>> tree(3, [tree(1), Function call: all <class 'function'>
... tree(2, [tree(1), arguments within >>> type(a.deposit)
return False
... tree(1)])]) parentheses <class 'method'>
return True
[3, [1], [2, [1], [1]]]
def is_leaf(tree):
Method invocation: >>> Account.deposit(a, 5)
return not branches(tree) def fib_tree(n):
One object before 10
def leaves(t): if n == 0 or n == 1: >>> a.deposit(2)
the dot and other Call expression
"""The leaf values in t. return tree(n) 12
arguments within
>>> leaves(fib_tree(5)) else: parentheses
[1, 0, 1, 0, 1, 1, 0, 1] left = fib_tree(n-2), Dot expression
""" right = fib_tree(n-1)
if is_leaf(t): fib_n = label(left) + label(right)
return [label(t)] <expression> . <name>
return tree(fib_n, [left, right])
else: The <expression> can be any valid Python expression.
return sum([leaves(b) for b in branches(t)], []) The <name> must be a simple name.
class Tree: Evaluates to the value of the attribute looked up by <name> in the object
def __init__(self, label, branches=[]): Built-in isinstance that is the value of the <expression>.
self.label = label function: returns True if To evaluate a dot expression:
for branch in branches: branch has a class that 1. Evaluate the <expression> to the left of the dot, which yields
assert isinstance(branch, Tree) is or inherits from Tree the object of the dot expression
self.branches = list(branches) 2. <name> is matched against the instance attributes of that object;
if an attribute with that name exists, its value is returned
def is_leaf(self): def fib_tree(n): 3. If not, <name> is looked up in the class, which yields a class
return not self.branches if n == 0 or n == 1:
attribute value
return Tree(n)
else:
4. That value is returned unless it is a function, in which case a
def leaves(tree): bound method is returned instead
left = fib_Tree(n-2)
"The leaf values in a tree."
right = fib_Tree(n-1)
if tree.is_leaf(): Assignment statements with a dot expression on their left-hand side affect
fib_n = left.label+right.label
return [tree.label] return Tree(fib_n,[left, right]) attributes for the object of that dot expression
else: • If the object is an instance, then assignment sets an instance attribute
return sum([leaves(b) for b in tree.branches], []) • If the object is a class, then assignment sets a class attribute
class Link: Some zero Account class interest: 0.02 0.04 0.05
empty = () length sequence attributes (withdraw, deposit, __init__)
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link) Instance balance: 0 Instance balance: 0
self.first = first Link instance Link instance attributes of holder: 'Jim' attributes of holder: 'Tom'
self.rest = rest jim_account interest: 0.08 tom_account
first: 4 first: 5
def __repr__(self): >>> jim_account = Account('Jim') >>> jim_account.interest = 0.08
if self.rest: rest: rest: >>> tom_account = Account('Tom') >>> jim_account.interest
rest = ', ' + repr(self.rest) >>> tom_account.interest 0.08
else: >>> s = Link(4, Link(5)) >>> tom_account.interest
0.02
rest = '' >>> s 0.04
>>> jim_account.interest
return 'Link('+repr(self.first)+rest+')' Link(4, Link(5)) >>> Account.interest = 0.05
0.02
>>> s.first >>> tom_account.interest
4 >>> Account.interest = 0.04
def __str__(self): 0.05
>>> s.rest >>> tom_account.interest
string = '<' >>> jim_account.interest
while self.rest is not Link.empty: Link(5) 0.04
>>> print(s) >>> jim_account.interest 0.08
string += str(self.first) + ' '
self = self.rest <4 5> 0.04
return string + str(self.first) + '>' >>> print(s.rest)
<5> class CheckingAccount(Account):
>>> s.rest.rest is Link.empty """A bank account that charges for withdrawals."""
True withdraw_fee = 1
Anatomy of a recursive function:
def sum_digits(n): interest = 0.01
• The def statement header is like any function "Sum the digits of positive integer n." def withdraw(self, amount):
• Conditional statements check for base cases
• Base cases are evaluated without recursive calls
if n < 10: return Account.withdraw(self, amount + self.withdraw_fee)
return n
• Recursive cases are evaluated with recursive calls else: or
all_but_last, last = n // 10, n % 10
return sum_digits(all_but_last) + last return super().withdraw( amount + self.withdraw_fee)

• Recursive decomposition: finding def count_partitions(n, m): To look up a name in a class:


simpler instances of a problem. if n == 0: 1. If it names an attribute in the class, return the attribute value.
• E.g., count_partitions(6, 4) return 1 2. Otherwise, look up the name in the base class, if there is one.
• Explore two possibilities: elif n < 0:
>>> ch = CheckingAccount('Tom') # Calls Account.__init__
• Use at least one 4 return 0
• Don't use any 4 elif m == 0: >>> ch.interest # Found in CheckingAccount
• Solve two simpler problems: return 0 0.01
• count_partitions(2, 4) else: >>> ch.deposit(20) # Found in Account
• count_partitions(6, 3) with_m = count_partitions(n-m, m) 20
• Tree recursion often involves without_m = count_partitions(n, m-1) >>> ch.withdraw(5) # Found in CheckingAccount
exploring different choices. return with_m + without_m 14

You might also like