Due by 11:59pm on Monday, 10/20
Submission: See Lab 1 for submission instructions. We have provided a hw6.py starter file for the questions below.
Readings: You might find the following references useful:
Create a class called VendingMachine
that represents a vending
machine for some product. A VendingMachine
object returns strings
describing its interactions. See the doctest below for examples:
class VendingMachine(object):
"""A vending machine that vends some product for some price.
>>> v = VendingMachine('candy', 10)
>>> v.vend()
'Machine is out of stock.'
>>> v.restock(2)
'Current candy stock: 2'
>>> v.vend()
'You must deposit $10 more.'
>>> v.deposit(7)
'Current balance: $7'
>>> v.vend()
'You must deposit $3 more.'
>>> v.deposit(5)
'Current balance: $12'
>>> v.vend()
'Here is your candy and $2 change.'
>>> v.deposit(10)
'Current balance: $10'
>>> v.vend()
'Here is your candy.'
>>> v.deposit(15)
'Machine is out of stock. Here is your $15.'
"""
"*** YOUR CODE HERE ***"
Create a class called MissManners
that promotes politeness among our
objects. A MissManners
object takes another object on construction.
It has one method, called ask
. It responds by calling methods on the
object it contains, but only if the caller said please first.
Hint: Your implementation will need to use the *args
notation that
allows functions to take a flexible number of arguments:
class MissManners(object):
"""A container class that only forward messages that say please.
>>> v = VendingMachine('teaspoon', 10)
>>> v.restock(2)
'Current teaspoon stock: 2'
>>> m = MissManners(v)
>>> m.ask('vend')
'You must learn to say please first.'
>>> m.ask('please vend')
'You must deposit $10 more.'
>>> m.ask('please deposit', 20)
'Current balance: $20'
>>> m.ask('now will you vend?')
'You must learn to say please first.'
>>> m.ask('please hand over a teaspoon')
'Thanks for asking, but I know not how to hand over a teaspoon'
>>> m.ask('please vend')
'Here is your teaspoon and $10 change.'
>>> really_fussy = MissManners(m)
>>> really_fussy.ask('deposit', 10)
'You must learn to say please first.'
>>> really_fussy.ask('please deposit', 10)
'Thanks for asking, but I know not how to deposit'
>>> really_fussy.ask('please please deposit', 10)
'Thanks for asking, but I know not how to please deposit'
>>> really_fussy.ask('please ask', 'please deposit', 10)
'Current balance: $10'
>>> fussy_three = MissManners(3)
>>> fussy_three.ask('add', 4)
'You must learn to say please first.'
>>> fussy_three.ask('please add', 4)
'Thanks for asking, but I know not how to add'
>>> fussy_three.ask('please __add__', 4)
7
"""
"*** YOUR CODE HERE ***"
Read Section 2.6 of Composing Programs. You can also watch the Fall 2012 lecture on this topic. 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:
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()