Practicing Classes#
Exercise 1 (shopping cart)#
Let’s write a simple shopping cart class – this will hold items that you intend to purchase as well as the amount, etc. And allow you to add / remove items, get a subtotal, etc.
We’ll use two classes: Item
will be a single item and ShoppingCart
will be the collection of items you wish to purchase.
First, our store needs an inventory – here’s what we have for sale:
INVENTORY_TEXT = """
apple, 0.60
banana, 0.20
grapefruit, 0.75
grapes, 1.99
kiwi, 0.50
lemon, 0.20
lime, 0.25
mango, 1.50
papaya, 2.95
pineapple, 3.50
blueberries, 1.99
blackberries, 2.50
peach, 0.50
plum, 0.33
clementine, 0.25
cantaloupe, 3.25
pear, 1.25
quince, 0.45
orange, 0.60
"""
# this will be a global -- convention is all caps
INVENTORY = {}
for line in INVENTORY_TEXT.splitlines():
if line.strip() == "":
continue
item, price = line.split(",")
INVENTORY[item] = float(price)
INVENTORY
{'apple': 0.6,
'banana': 0.2,
'grapefruit': 0.75,
'grapes': 1.99,
'kiwi': 0.5,
'lemon': 0.2,
'lime': 0.25,
'mango': 1.5,
'papaya': 2.95,
'pineapple': 3.5,
'blueberries': 1.99,
'blackberries': 2.5,
'peach': 0.5,
'plum': 0.33,
'clementine': 0.25,
'cantaloupe': 3.25,
'pear': 1.25,
'quince': 0.45,
'orange': 0.6}
Item
#
Here’s the start of an item class – we want it to hold the name and quantity.
You should have the following features:
the name should be something in our inventory
Our shopping cart will include a list of all the items we want to buy, so we want to be able to check for duplicates. Implement the equal test,
==
, using__eq__
we’ll want to consolidate dupes, so implement the
+
operator, using__add__
so we can add items together in our shopping cart. Note, add should raise a ValueError if you try to add twoItems
that don’t have the same name.
Here’s a start:
class Item(object):
""" an item to buy """
def __init__(self, name, quantity=1):
if name not in INVENTORY:
raise ValueError
self.name = name
self.quantity = quantity
def __repr__(self):
pass
def __eq__(self, other):
pass
def __add__(self, other):
pass
Here are some tests your code should pass:
a = Item("apple", 10)
b = Item("banana", 20)
c = Item("apple", 20)
# won't work
a + b
# will work
a += c
a
a == b
a == c
How do they behave in a list?
items = []
items.append(a)
items.append(b)
items
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/IPython/core/formatters.py:711, in PlainTextFormatter.__call__(self, obj)
704 stream = StringIO()
705 printer = pretty.RepresentationPrinter(stream, self.verbose,
706 self.max_width, self.newline,
707 max_seq_length=self.max_seq_length,
708 singleton_pprinters=self.singleton_printers,
709 type_pprinters=self.type_printers,
710 deferred_pprinters=self.deferred_printers)
--> 711 printer.pretty(obj)
712 printer.flush()
713 return stream.getvalue()
File /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/IPython/lib/pretty.py:394, in RepresentationPrinter.pretty(self, obj)
391 for cls in _get_mro(obj_class):
392 if cls in self.type_pprinters:
393 # printer registered in self.type_pprinters
--> 394 return self.type_pprinters[cls](obj, self, cycle)
395 else:
396 # deferred printer
397 printer = self._in_deferred_types(cls)
File /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/IPython/lib/pretty.py:649, in _seq_pprinter_factory.<locals>.inner(obj, p, cycle)
647 p.text(',')
648 p.breakable()
--> 649 p.pretty(x)
650 if len(obj) == 1 and isinstance(obj, tuple):
651 # Special case for 1-item tuples.
652 p.text(',')
File /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/IPython/lib/pretty.py:419, in RepresentationPrinter.pretty(self, obj)
408 return meth(obj, self, cycle)
409 if (
410 cls is not object
411 # check if cls defines __repr__
(...)
417 and callable(_safe_getattr(cls, "__repr__", None))
418 ):
--> 419 return _repr_pprint(obj, self, cycle)
421 return _default_pprint(obj, self, cycle)
422 finally:
File /opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/IPython/lib/pretty.py:787, in _repr_pprint(obj, p, cycle)
785 """A pprint that just redirects to the normal repr function."""
786 # Find newlines and replace them with p.break_()
--> 787 output = repr(obj)
788 lines = output.splitlines()
789 with p.group():
TypeError: __repr__ returned non-string (type NoneType)
c in items
False
ShoppingCart
#
Now we want to create a shopping cart. The main thing it will do is hold a list of items.
class ShoppingCart(object):
def __init__(self):
self.items = []
def subtotal(self):
""" return a subtotal of our items """
pass
def add(self, name, quantity):
""" add an item to our cart """
pass
def remove(self, name):
""" remove all of item name from the cart """
pass
def report(self):
""" print a summary of the cart """
pass
Here are some tests
sc = ShoppingCart()
sc.add("orange", 19)
sc.add("apple", 2)
sc.report()
sc.add("apple", 9)
sc.report()
sc.subtotal()
sc.remove("apple")
sc.report()
Exercise 2: Poker Odds#
Use the deck of cards class from the notebook we worked through outside of class to write a Monte Carlo code that plays a lot of hands of straight poker (like 100,000). Count how many of these hands has a particular poker hand (like 3-of-a-kind). The ratio of # of hands with 3-of-a-kind to total hands is an approximation to the odds of getting a 3-of-a-kind in poker.
You’ll want to copy-paste those classes into a .py
file to allow you to import and reuse them here
Exercise 3: Tic-Tac-Toe#
Revisit the tic-tac-toe game you developed in the functions exercises but now write it as a class with methods to do each of the main steps.