Lab 7: OOP
Due by 11:59pm on Friday, October 24.
Starter Files
Download lab07.zip.
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.
Object-Oriented Programming
Here's a refresher on Object-Oriented Programming. It's okay to skip directly to the questions and refer back here if you get stuck.
Object-oriented programming (OOP) uses objects and classes to organize programs. Here's an example of a class:
class Car:
max_tires = 4
def __init__(self, color):
self.tires = Car.max_tires
self.color = color
def drive(self):
if self.tires < Car.max_tires:
return self.color + ' car cannot drive!'
return self.color + ' car goes vroom!'
def pop_tire(self):
if self.tires > 0:
self.tires -= 1
Class: The type of an object. The Car class (shown above) describes the characteristics of all Car
objects.
Object: A single instance of a class. In Python, a new object is created by calling a class.
>>> ferrari = Car('red')
Here, ferrari is a name bound to a Car object.
Class attribute: A variable that belongs to a class and is accessed via dot notation. The Car class has a max_tires attribute.
>>> Car.max_tires
4
Instance attribute: A variable that belongs to a particular object. Each Car object has a tires attribute and a color attribute. Like class attributes, instance attributes are accessed via dot notation.
>>> ferrari.color
'red'
>>> ferrari.tires
4
>>> ferrari.color = 'green'
>>> ferrari.color
'green'
Method: A function that belongs to an object and is called via dot notation. By convention, the first parameter of a method is self.
When one of an object's methods is called, the object is implicitly provided as the argument for self. For example, the drive method of the ferrari object is called with empty parentheses because self is implicitly bound to the ferrari object.
>>> ferrari = Car('red')
>>> ferrari.drive()
'red car goes vroom!'
We can also call the original Car.drive function. The original function does not belong to any particular Car object, so we must provide an explicit argument for self.
>>> ferrari = Car('red')
>>> Car.drive(ferrari)
'red car goes vroom!'
__init__: A special function that is called automatically when a new instance of a class is created.
Notice how the drive method takes in self as an argument, but it
looks like we didn't pass one in! This is because the dot notation
implicitly passes in ferrari as self for us. So in this example, self is bound to the
object called ferrari in the global frame.
To evaluate the expression Car('red'), Python creates a new Car object. Then, Python calls the __init__ function of the Car class with self bound to the new object and color bound to 'red'.
Q1: Smart Fridge
The SmartFridge class is used by smart
refrigerators to track which items are in the fridge
and let owners know when an item has run out.
The class internally uses a dictionary to store items,
where each key is the item name and the value is the current quantity.
The add_item method should add the given quantity
of the given item and report the current quantity.
You can assume that the use_item method will only be called on
items that are already in the fridge, and it should use up
the given quantity of the given item. If the quantity would fall to or below zero, it should only use up to the remaining quantity, and remind the owner to buy more of that item.
Finish implementing the SmartFridge class definition
so that its add_item and use_item methods work as specified by the doctests.
class SmartFridge:
""""
>>> fridgey = SmartFridge()
>>> fridgey.add_item('Mayo', 1)
'I now have 1 Mayo'
>>> fridgey.add_item('Mayo', 2)
'I now have 3 Mayo'
>>> fridgey.use_item('Mayo', 2.5)
'I have 0.5 Mayo left'
>>> fridgey.use_item('Mayo', 0.5)
'Oh no, we need more Mayo!'
>>> fridgey.add_item('Eggs', 12)
'I now have 12 Eggs'
>>> fridgey.use_item('Eggs', 15)
'Oh no, we need more Eggs!'
>>> fridgey.add_item('Eggs', 1)
'I now have 1 Eggs'
"""
def __init__(self):
self.items = {}
def add_item(self, item, quantity):
"*** YOUR CODE HERE ***"
def use_item(self, item, quantity):
"*** YOUR CODE HERE ***"
You may find Python's formatted string literals, or f-strings useful. A quick example:
>>> feeling = 'love' >>> course = '61A!' >>> f'I {feeling} {course}' 'I love 61A!'
Use Ok to test your code:
python3 ok -q SmartFridge
If you're curious about alternate methods of string formatting, you can also check out an older method of Python string formatting. A quick example:
>>> ten, twenty, thirty = 10, 'twenty', [30] >>> '{0} plus {1} is {2}'.format(ten, twenty, thirty) '10 plus twenty is [30]'
Q2: Person
Modify the following Person class to add a repeat method, which
repeats the last thing said. See the doctests for an example of its
use.
Hint: you will have to modify other methods as well, not just the
repeatmethod.
class Person:
"""Person class.
>>> steven = Person("Steven")
>>> steven.repeat() # initialized person has the below starting repeat phrase!
'I squirreled it away before it could catch on fire.'
>>> steven.say("Hello")
'Hello'
>>> steven.repeat()
'Hello'
>>> steven.greet()
'Hello, my name is Steven'
>>> steven.repeat()
'Hello, my name is Steven'
>>> steven.ask("preserve abstraction barriers")
'Would you please preserve abstraction barriers'
>>> steven.repeat()
'Would you please preserve abstraction barriers'
"""
def __init__(self, name):
self.name = name
"*** YOUR CODE HERE ***"
def say(self, stuff):
"*** YOUR CODE HERE ***"
return stuff
def ask(self, stuff):
return self.say("Would you please " + stuff)
def greet(self):
return self.say("Hello, my name is " + self.name)
def repeat(self):
"*** YOUR CODE HERE ***"
Use Ok to test your code:
python3 ok -q Person
Q3: Mint
A mint is a place where coins are made. In this question, you'll implement a Mint class that can output a Coin with the correct year and worth.
- Each
Mintinstance has ayearstamp. Theupdatemethod sets theyearstamp of the instance to thepresent_yearclass attribute of theMintclass. - The
createmethod takes a subclass ofCoin(not an instance!), then creates and returns an instance of that subclass stamped with theMint's year (which may be different fromMint.present_yearif it has not been updated.) - A
Coin'sworthmethod returns thecentsvalue of the coin plus one extra cent for each year of age beyond 50. A coin's age can be determined by subtracting the coin's year from thepresent_yearclass attribute of theMintclass.
class Mint:
"""A mint creates coins by stamping on years.
The update method sets the mint's stamp to Mint.present_year.
>>> mint = Mint()
>>> mint.year
2025
>>> dime = mint.create(Dime)
>>> dime.year
2025
>>> Mint.present_year = 2105 # Time passes
>>> nickel = mint.create(Nickel)
>>> nickel.year # The mint has not updated its stamp yet
2025
>>> nickel.worth() # 5 cents + (80 - 50 years)
35
>>> mint.update() # The mint's year is updated to 2105
>>> Mint.present_year = 2180 # More time passes
>>> mint.create(Dime).worth() # 10 cents + (75 - 50 years)
35
>>> Mint().create(Dime).worth() # A new mint has the current year
10
>>> dime.worth() # 10 cents + (155 - 50 years)
115
>>> Dime.cents = 20 # Upgrade all dimes!
>>> dime.worth() # 20 cents + (155 - 50 years)
125
"""
present_year = 2025
def __init__(self):
self.update()
def create(self, coin):
"*** YOUR CODE HERE ***"
def update(self) -> None:
"*** YOUR CODE HERE ***"
class Coin:
cents = None # will be provided by subclasses, but not by Coin itself
def __init__(self, year: int):
self.year = year
def worth(self) -> int:
"*** YOUR CODE HERE ***"
class Nickel(Coin):
cents = 5
class Dime(Coin):
cents = 10
Use Ok to test your code:
python3 ok -q Mint
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.