Homework 6 Solutions

Solution Files

Questions

Object Oriented Programming

Q1: Next Fibonacci Object

Implement the next method of the Fib class. For this class, the value attribute is a Fibonacci number. The next method returns a Fib instance whose value is the next Fibonacci number. The next method should take only constant time.

Note that in the doctests, nothing is being printed out. Rather, each call to .next() returns a Fib instance, which is represented in the interpreter as the value of that instance (see the __repr__ method).

Hint: Keep track of the previous number by setting a new instance attribute inside next.

class Fib():
    """A Fibonacci number.

    >>> start = Fib()
    >>> start
    0
    >>> start.next()
    1
    >>> start.next().next()
    1
    >>> start.next().next().next()
    2
    >>> start.next().next().next().next()
    3
    >>> start.next().next().next().next().next()
    5
    >>> start.next().next().next().next().next().next()
    8
    >>> start.next().next().next().next().next().next() # Ensure start isn't changed
    8
    """

    def __init__(self, value=0):
        self.value = value

    def next(self):
if self.value == 0: result = Fib(1) else: result = Fib(self.value + self.previous) result.previous = self.value return result
def __repr__(self): return str(self.value)

Use Ok to test your code:

python3 ok -q Fib

Remember that next must return a Fibonacci object! With this in mind, our first goal is to calculate the next Fibonacci object and return it. One approach is to figure out the base case (self.value == 0) and then decide what information is needed for the following call to next.

You might also note that storing the current value makes the solution look very similar to the iterative version of the fib problem.

Video walkthrough: https://youtu.be/-_bn87W4oOE

Q2: Vending Machine

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:
    """A vending machine that vends some product for some price.

    >>> v = VendingMachine('candy', 10)
    >>> v.vend()
    'Machine is out of stock.'
    >>> v.deposit(15)
    'Machine is out of stock. Here is your $15.'
    >>> 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.'

    >>> w = VendingMachine('soda', 2)
    >>> w.restock(3)
    'Current soda stock: 3'
    >>> w.restock(3)
    'Current soda stock: 6'
    >>> w.deposit(2)
    'Current balance: $2'
    >>> w.vend()
    'Here is your soda.'
    """
def __init__(self, product, price): self.product = product self.price = price self.stock = 0 self.balance = 0 def restock(self, n): self.stock += n return 'Current {0} stock: {1}'.format(self.product, self.stock) def deposit(self, n): if self.stock == 0: return 'Machine is out of stock. Here is your ${0}.'.format(n) self.balance += n return 'Current balance: ${0}'.format(self.balance) def vend(self): if self.stock == 0: return 'Machine is out of stock.' difference = self.price - self.balance if difference > 0: return 'You must deposit ${0} more.'.format(difference) message = 'Here is your {0}'.format(self.product) if difference != 0: message += ' and ${0} change'.format(-difference) self.balance = 0 self.stock -= 1 return message + '.'

You may find Python string formatting syntax useful. A quick example:

>>> ten, twenty, thirty = 10, 'twenty', [30]
>>> '{0} plus {1} is {2}'.format(ten, twenty, thirty)
'10 plus twenty is [30]'

Use Ok to test your code:

python3 ok -q VendingMachine

Reading through the doctests, it should be clear which functions we should add to ensure that the vending machine class behaves correctly.

__init__

  • This can be difficult to fill out at first. Both product and price seem pretty obvious to keep around, but stock and balance are quantities that are needed only after attempting other functions.

restock

  • Even though v.restock(2) takes only one argument in the doctest, remember that self is bound to the object the restock method is invoked on. Therefore, this function has two parameters.
  • While implementing this function, you will probably realize that you would like to keep track of the stock somewhere. While it might be possible to set the stock in this function as an instance attribute, it would lose whatever the old stock was. Therefore, the natural solution is to initialize stock in the constructor, and then update it in restock.

deposit

  • This behaves very similarly to restock. See comments above.
  • Also yes, this is quite the expensive vending machine.

vend

  • The trickiest thing here is to make sure we handle all the cases. You may find it helpful when implementing a problem like this to keep track of all the errors we run into in the doctest.

    1. No stock
    2. Not enough balance
    3. Leftover balance after purchase (return change to customer)
    4. No leftover balance after purchase
  • We use some string concatenation at the end when handling case 3 and 4 to try and reduce the amount of code. This isn't necessary for correctness -- it's ok to have something like:

    if difference != 0:
        return ...
    else:
        return ...

    Of course, that would require decrementing the balance and stock beforehand.

Video walkthrough: https://youtu.be/7A8WtnX89z4