Skip to content

Commit 667d8c5

Browse files
committed
final version for OSCON
1 parent f69446a commit 667d8c5

File tree

4 files changed

+114
-5
lines changed

4 files changed

+114
-5
lines changed

docs/strategy.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ Rethinking strategy
1919
-----------------
2020

2121
.. literalinclude:: ../exercises/strategy/strategy2.py
22+
23+
24+
``strategy3.py``
25+
-----------------
26+
27+
.. literalinclude:: ../exercises/strategy/strategy3.py

exercises/strategy/promotions.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
def fidelity_promo(order):
3+
"""5% discount for customers with 1000 or more fidelity points"""
4+
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
5+
6+
7+
def bulk_item_promo(order):
8+
"""10% discount for each LineItem with 20 or more units"""
9+
discount = 0
10+
for item in order.cart:
11+
if item.quantity >= 20:
12+
discount += item.total() * .1
13+
return discount
14+
15+
def large_order_promo(order):
16+
"""7% discount for orders with 10 or more distinct items"""
17+
distinct_items = {item.product for item in order.cart}
18+
if len(distinct_items) >= 10:
19+
return order.total() * .07
20+
return 0

exercises/strategy/strategy2.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
>>> Order(joe, cart, large_order_promo)
2424
<Order total: 42.00 due: 42.00>
2525
26-
# BEGIN STRATEGY_BEST_TESTS
26+
Tests for ``best_promo`` strategy::
2727
2828
>>> Order(joe, long_order, best_promo) # <1>
2929
<Order total: 10.00 due: 9.30>
@@ -32,7 +32,6 @@
3232
>>> Order(ann, cart, best_promo) # <3>
3333
<Order total: 42.00 due: 39.90>
3434
35-
# END STRATEGY_BEST_TESTS
3635
"""
3736

3837
from collections import namedtuple
@@ -96,13 +95,10 @@ def large_order_promo(order):
9695
return order.total() * .07
9796
return 0
9897

99-
# BEGIN STRATEGY_BEST
10098

10199
promos = [fidelity_promo, bulk_item_promo, large_order_promo] # <1>
102100

103101
def best_promo(order): # <2>
104102
"""Select best discount available
105103
"""
106104
return max(promo(order) for promo in promos) # <3>
107-
108-
# END STRATEGY_BEST

exercises/strategy/strategy3.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# strategy_best3.py
2+
# Strategy pattern -- function-based implementation
3+
# selecting best promotion from imported module
4+
5+
"""
6+
>>> from promotions import *
7+
>>> joe = Customer('John Doe', 0)
8+
>>> ann = Customer('Ann Smith', 1100)
9+
>>> cart = [LineItem('banana', 4, .5),
10+
... LineItem('apple', 10, 1.5),
11+
... LineItem('watermellon', 5, 5.0)]
12+
>>> Order(joe, cart, fidelity_promo)
13+
<Order total: 42.00 due: 42.00>
14+
>>> Order(ann, cart, fidelity_promo)
15+
<Order total: 42.00 due: 39.90>
16+
>>> banana_cart = [LineItem('banana', 30, .5),
17+
... LineItem('apple', 10, 1.5)]
18+
>>> Order(joe, banana_cart, bulk_item_promo)
19+
<Order total: 30.00 due: 28.50>
20+
>>> long_order = [LineItem(str(item_code), 1, 1.0)
21+
... for item_code in range(10)]
22+
>>> Order(joe, long_order, large_order_promo)
23+
<Order total: 10.00 due: 9.30>
24+
>>> Order(joe, cart, large_order_promo)
25+
<Order total: 42.00 due: 42.00>
26+
27+
Tests for ``best_promo`` strategy::
28+
29+
>>> Order(joe, long_order, best_promo)
30+
<Order total: 10.00 due: 9.30>
31+
>>> Order(joe, banana_cart, best_promo)
32+
<Order total: 30.00 due: 28.50>
33+
>>> Order(ann, cart, best_promo)
34+
<Order total: 42.00 due: 39.90>
35+
36+
"""
37+
38+
from collections import namedtuple
39+
import inspect
40+
41+
import promotions
42+
43+
Customer = namedtuple('Customer', 'name fidelity')
44+
45+
46+
class LineItem:
47+
48+
def __init__(self, product, quantity, price):
49+
self.product = product
50+
self.quantity = quantity
51+
self.price = price
52+
53+
def total(self):
54+
return self.price * self.quantity
55+
56+
57+
class Order: # the Context
58+
59+
def __init__(self, customer, cart, promotion=None):
60+
self.customer = customer
61+
self.cart = list(cart)
62+
self.promotion = promotion
63+
64+
def total(self):
65+
if not hasattr(self, '__total'):
66+
self.__total = sum(item.total() for item in self.cart)
67+
return self.__total
68+
69+
def due(self):
70+
if self.promotion is None:
71+
discount = 0
72+
else:
73+
discount = self.promotion(self)
74+
return self.total() - discount
75+
76+
def __repr__(self):
77+
fmt = '<Order total: {:.2f} due: {:.2f}>'
78+
return fmt.format(self.total(), self.due())
79+
80+
81+
promos = [func for name, func in
82+
inspect.getmembers(promotions, inspect.isfunction)]
83+
84+
def best_promo(order):
85+
"""Select best discount available
86+
"""
87+
return max(promo(order) for promo in promos)

0 commit comments

Comments
 (0)