Due by 11:59pm on Thursday, 4/16
Download extra03.zip. Inside the archive, you will find a file called extra03.py, along with a copy of the OK autograder.
Submission: When you are done, submit with
python3 ok --submit
. You may submit more than once before
the deadline; only the final submission will be scored.
The ok
program helps you test your code and track your progress.
The first time you run the autograder, you will be asked to log in with your
@berkeley.edu account using your web browser. Please do so. Each time you run
ok, it will back up your work and progress on our servers.
You can run all the doctests with the following command:
python3 ok
To test a specific question, use the -q
option with the
name of the function:
python3 ok -q <function>
By default, only tests that fail will appear. If you
want to see how you did on all tests, you can use the -v
option:
python3 ok -v
If you do not want to send your progress to our server or you have any
problems logging in, add the --local
flag to block all
communication:
python3 ok --local
When you are ready to submit, run ok
with the
--submit
option:
python3 ok --submit
Readings: You might find the following references useful:
This homework is required for the "extra lectures" track of CS 98: Additional Topics on the Structure and Interpretation of Computer Programs.
You can watch the Fall 2012 lecture on this topic, in addition to the extra lecture screencast. Add multiple inheritance to the function-based object system described in that section. You will need to make the following changes:
'mro'
that returns the method
resolution order for the class.'get'
message) should follow the method resolution order.Choose a method resolution order that ensures a name is never looked up in a base class before one of its subclasses. You can read about different alternatives in this blog post on the history of multiple inheritance in Python by Guido van Rossum. Any method you choose that passes the tests is acceptable.
def make_instance(some_class):
"""Return a new object instance of some_class."""
def get_value(name):
if name in attributes:
return attributes[name]
else:
value = some_class['get'](name)
return bind_method(value, instance)
def set_value(name, value):
attributes[name] = value
attributes = {}
instance = {'get': get_value, 'set': set_value}
return instance
def bind_method(value, instance):
"""Return value or a bound method if value is callable."""
if callable(value):
def method(*args):
return value(instance, *args)
return method
else:
return value
def make_class(attributes, base_classes=()):
"""Return a new class with attributes.
attributes -- class attributes
base_classes -- a sequence of classes
"""
"*** YOUR CODE HERE ***"
def init_instance(some_class, *args):
"""Return a new instance of some_class, initialized with args."""
instance = make_instance(some_class)
init = some_class['get']('__init__')
if init:
init(instance, *args)
return instance
# AsSeenOnTVAccount example from lecture.
def make_account_class():
"""Return the Account class, which has deposit and withdraw methods."""
interest = 0.02
def __init__(self, account_holder):
self['set']('holder', account_holder)
self['set']('balance', 0)
def deposit(self, amount):
"""Increase the account balance by amount and return the new balance."""
new_balance = self['get']('balance') + amount
self['set']('balance', new_balance)
return self['get']('balance')
def withdraw(self, amount):
"""Decrease the account balance by amount and return the new balance."""
balance = self['get']('balance')
if amount > balance:
return 'Insufficient funds'
self['set']('balance', balance - amount)
return self['get']('balance')
return make_class(locals())
Account = make_account_class()
def make_checking_account_class():
"""Return the CheckingAccount class, which imposes a $1 withdrawal fee.
>>> checking = CheckingAccount['new']('Jack')
>>> checking['get']('interest')
0.01
>>> checking['get']('deposit')(20)
20
>>> checking['get']('withdraw')(5)
14
"""
interest = 0.01
withdraw_fee = 1
def withdraw(self, amount):
fee = self['get']('withdraw_fee')
return Account['get']('withdraw')(self, amount + fee)
return make_class(locals(), [Account])
CheckingAccount = make_checking_account_class()
def make_savings_account_class():
"""Return the SavingsAccount class, which imposes a $2 deposit fee.
>>> savings = SavingsAccount['new']('Jack')
>>> savings['get']('interest')
0.02
>>> savings['get']('deposit')(20)
18
>>> savings['get']('withdraw')(5)
13
"""
deposit_fee = 2
def deposit(self, amount):
fee = self['get']('deposit_fee')
return Account['get']('deposit')(self, amount - fee)
return make_class(locals(), [Account])
SavingsAccount = make_savings_account_class()
def make_as_seen_on_tv_account_class():
"""Return an account with lots of fees and a free dollar.
>>> such_a_deal = AsSeenOnTVAccount['new']('Jack')
>>> such_a_deal['get']('balance')
1
>>> such_a_deal['get']('interest')
0.01
>>> such_a_deal['get']('deposit')(20)
19
>>> such_a_deal['get']('withdraw')(5)
13
"""
def __init__(self, account_holder):
self['set']('holder', account_holder)
self['set']('balance', 1)
return make_class(locals(), [CheckingAccount, SavingsAccount])
AsSeenOnTVAccount = make_as_seen_on_tv_account_class()