Homework 7: OOP
Due by 11:59pm on Wednesday, April 2
Instructions
Download hw07.zip. Inside the archive, you will find a file called
hw07.py, along with a copy of the ok
autograder.
Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the final submission will be scored. Check that you have successfully submitted your code on Gradescope. See Lab 0 for more instructions on submitting assignments.
Using Ok: If you have any questions about using Ok, please refer to this guide.
Grading: Homework is graded based on correctness. Each incorrect problem will decrease the total score by one point. This homework is out of 2 points.
Midsemester Feedback Survey
Please fill out the mid-semester feedback form. If 75% of the class completes this form by Monday 3/31 at 11:59 PM, everyone will receive 1 point of extra credit! If this goal is not met, nobody will receive the extra point.
Required Questions
Getting Started Videos
These videos may provide some helpful direction for tackling the coding problems on this assignment.
To see these videos, you should be logged into your berkeley.edu email.
Q1: Email
An email system has three classes: Email
, Server
, and Client
. A Client
can
compose
an email, which it will send
to the Server
. The Server
then delivers it to the
inbox
of another Client
. To achieve this, a Server
has a dictionary called
clients
that maps the name of the Client
to the Client
instance.
Assume that a Client
never changes the Server
that it uses, and it can only compose an Email
using that Server
.
Fill in the definitions below to finish the implementation! The Email
class
has been completed for you.
Important: Before you start, make sure you read the entire code snippet to understand the relationships between the classes, and pay attention to the parameter type of the methods. Think about what variables you have access to in each method and how can you use them to access the other classes and their methods.
Note:
- The
sender
parameter from the__init__(self, msg, sender, recipient_name)
method in theEmail
class is aClient
instance. - The
client
parameter from theregister_client(self, client)
method in theServer
class is aClient
instance. - The
email
parameter from thesend(self, email)
method in theServer
class is anEmail
instance.
class Email:
"""An email has the following instance attributes:
msg (str): the contents of the message
sender (Client): the client that sent the email
recipient_name (str): the name of the recipient (another client)
"""
def __init__(self, msg, sender, recipient_name):
self.msg = msg
self.sender = sender
self.recipient_name = recipient_name
class Server:
"""Each Server has one instance attribute called clients that is a
dictionary from client names to client objects.
>>> s = Server()
>>> # Dummy client class implementation for testing only
>>> class Client:
... def __init__(self, server, name):
... self.inbox = []
... self.server = server
... self.name = name
>>> a = Client(s, 'Alice')
>>> b = Client(s, 'Bob')
>>> s.register_client(a)
>>> s.register_client(b)
>>> len(s.clients) # we have registered 2 clients
2
>>> all([type(c) == str for c in s.clients.keys()]) # The keys in self.clients should be strings
True
>>> all([type(c) == Client for c in s.clients.values()]) # The values in self.clients should be Client instances
True
>>> new_a = Client(s, 'Alice') # a new client with the same name as an existing client
>>> s.register_client(new_a)
>>> len(s.clients) # the key of a dictionary must be unique
2
>>> s.clients['Alice'] is new_a # the value for key 'Alice' should now be updated to the new client new_a
True
>>> e = Email("I love 61A", b, 'Alice')
>>> s.send(e)
>>> len(new_a.inbox) # one email has been sent to new Alice
1
>>> type(new_a.inbox[0]) == Email # a Client's inbox is a list of Email instances
True
"""
def __init__(self):
self.clients = {}
def send(self, email):
"""Append the email to the inbox of the client it is addressed to.
email is an instance of the Email class.
"""
____.inbox.append(email)
def register_client(self, client):
"""Add a client to the clients mapping (which is a
dictionary from client names to client instances).
client is an instance of the Client class.
"""
____[____] = ____
class Client:
"""A client has a server, a name (str), and an inbox (list).
>>> s = Server()
>>> a = Client(s, 'Alice')
>>> b = Client(s, 'Bob')
>>> a.compose('Hello, World!', 'Bob')
>>> b.inbox[0].msg
'Hello, World!'
>>> a.compose('CS 61A Rocks!', 'Bob')
>>> len(b.inbox)
2
>>> b.inbox[1].msg
'CS 61A Rocks!'
>>> b.inbox[1].sender.name
'Alice'
"""
def __init__(self, server, name):
self.inbox = []
self.server = server
self.name = name
server.register_client(____)
def compose(self, message, recipient_name):
"""Send an email with the given message to the recipient."""
email = Email(message, ____, ____)
self.server.send(email)
There are two
ok
tests for this problem. Both tests must pass in order to receive full credit. You should run them in the order they are presented. Thepython3 ok -q Server
test will test theServer
class implementation, and it does not require a correct implementation of theClient
class. Thepython3 ok -q Client
test will test both theServer
andClient
class implementations. So, make sure to test yourServer
class implementation first before testing theClient
class.
Use Ok to test your code:
python3 ok -q Server
python3 ok -q Client
Q2: Vending Machine
In this question you'll create a vending machine that sells a single product and provides change when needed.
Implement the VendingMachine
class, which models a vending machine for one specific product.
The methods of a VendingMachine
object return strings to describe the machine’s status and operations.
Ensure that your output matches exactly with the strings provided in the doctests, including punctuation and spacing.
You may find Python's formatted string literals, or f-strings useful. A quick example:
>>> feeling = 'love' >>> course = 'Data C88C!' >>> combined_string = f'I {feeling} {course}' >>> combined_string 'I love Data C88C!'
class VendingMachine:
"""A vending machine that vends some product for some price.
>>> v = VendingMachine('candy', 10)
>>> v.vend()
'Nothing left to vend. Please restock.'
>>> v.add_funds(15)
'Nothing left to vend. Please restock. Here is your $15.'
>>> v.restock(2)
'Current candy stock: 2'
>>> v.vend()
'Please add $10 more funds.'
>>> v.add_funds(7)
'Current balance: $7'
>>> v.vend()
'Please add $3 more funds.'
>>> v.add_funds(5)
'Current balance: $12'
>>> v.vend()
'Here is your candy and $2 change.'
>>> v.add_funds(10)
'Current balance: $10'
>>> v.vend()
'Here is your candy.'
>>> v.add_funds(15)
'Nothing left to vend. Please restock. Here is your $15.'
>>> w = VendingMachine('soda', 2)
>>> w.restock(3)
'Current soda stock: 3'
>>> w.restock(3)
'Current soda stock: 6'
>>> w.add_funds(2)
'Current balance: $2'
>>> w.vend()
'Here is your soda.'
"""
def __init__(self, product, price):
"""Set the product and its price, as well as other instance attributes."""
"*** YOUR CODE HERE ***"
def restock(self, n):
"""Add n to the stock and return a message about the updated stock level.
E.g., Current candy stock: 3
"""
"*** YOUR CODE HERE ***"
def add_funds(self, n):
"""If the machine is out of stock, return a message informing the user to restock
(and return their n dollars).
E.g., Nothing left to vend. Please restock. Here is your $4.
Otherwise, add n to the balance and return a message about the updated balance.
E.g., Current balance: $4
"""
"*** YOUR CODE HERE ***"
def vend(self):
"""Dispense the product if there is sufficient stock and funds and
return a message. Update the stock and balance accordingly.
E.g., Here is your candy and $2 change.
If not, return a message suggesting how to correct the problem.
E.g., Nothing left to vend. Please restock.
Please add $3 more funds.
"""
"*** YOUR CODE HERE ***"
Use Ok to test your code:
python3 ok -q VendingMachine
Check Your Score Locally
You can locally check your score on each question of this assignment by running
python3 ok --score
This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.
Submit Assignment
Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.