updated from Atlas
This commit is contained in:
33
07-closure-deco/average.py
Normal file
33
07-closure-deco/average.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
>>> avg = make_averager()
|
||||
>>> avg(10)
|
||||
10.0
|
||||
>>> avg(11)
|
||||
10.5
|
||||
>>> avg(12)
|
||||
11.0
|
||||
>>> avg.__code__.co_varnames
|
||||
('new_value', 'total')
|
||||
>>> avg.__code__.co_freevars
|
||||
('series',)
|
||||
>>> avg.__closure__ # doctest: +ELLIPSIS
|
||||
(<cell at 0x...: list object at 0x...>,)
|
||||
>>> avg.__closure__[0].cell_contents
|
||||
[10, 11, 12]
|
||||
"""
|
||||
|
||||
DEMO = """
|
||||
>>> avg.__closure__
|
||||
(<cell at 0x107a44f78: list object at 0x107a91a48>,)
|
||||
"""
|
||||
|
||||
|
||||
def make_averager():
|
||||
series = []
|
||||
|
||||
def averager(new_value):
|
||||
series.append(new_value)
|
||||
total = sum(series)
|
||||
return total/len(series)
|
||||
|
||||
return averager
|
||||
21
07-closure-deco/average_oo.py
Normal file
21
07-closure-deco/average_oo.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
>>> avg = Averager()
|
||||
>>> avg(10)
|
||||
10.0
|
||||
>>> avg(11)
|
||||
10.5
|
||||
>>> avg(12)
|
||||
11.0
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class Averager():
|
||||
|
||||
def __init__(self):
|
||||
self.series = []
|
||||
|
||||
def __call__(self, new_value):
|
||||
self.series.append(new_value)
|
||||
total = sum(self.series)
|
||||
return total/len(self.series)
|
||||
18
07-closure-deco/clockdeco_demo.py
Normal file
18
07-closure-deco/clockdeco_demo.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# clockdeco_demo.py
|
||||
|
||||
import time
|
||||
from clockdeco import clock
|
||||
|
||||
@clock
|
||||
def snooze(seconds):
|
||||
time.sleep(seconds)
|
||||
|
||||
@clock
|
||||
def factorial(n):
|
||||
return 1 if n < 2 else n*factorial(n-1)
|
||||
|
||||
if __name__=='__main__':
|
||||
print('*' * 40, 'Calling snooze(.123)')
|
||||
snooze(.123)
|
||||
print('*' * 40, 'Calling factorial(6)')
|
||||
print('6! =', factorial(6))
|
||||
40
07-closure-deco/clockdeco_param.py
Normal file
40
07-closure-deco/clockdeco_param.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# clockdeco_param.py
|
||||
|
||||
"""
|
||||
>>> snooze(.1) # doctest: +ELLIPSIS
|
||||
[0.101...s] snooze(0.1) -> None
|
||||
>>> clock('{name}: {elapsed}')(time.sleep)(.2) # doctest: +ELLIPSIS
|
||||
sleep: 0.20...
|
||||
>>> clock('{name}({args}) dt={elapsed:0.3f}s')(time.sleep)(.2)
|
||||
sleep(0.2) dt=0.201s
|
||||
"""
|
||||
|
||||
# BEGIN CLOCKDECO_PARAM
|
||||
import time
|
||||
|
||||
DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args}) -> {result}'
|
||||
|
||||
def clock(fmt=DEFAULT_FMT): # <1>
|
||||
def decorate(func): # <2>
|
||||
def clocked(*_args): # <3>
|
||||
t0 = time.time()
|
||||
_result = func(*_args) # <4>
|
||||
elapsed = time.time() - t0
|
||||
name = func.__name__
|
||||
args = ', '.join(repr(arg) for arg in _args) # <5>
|
||||
result = repr(_result) # <6>
|
||||
print(fmt.format(**locals())) # <7>
|
||||
return _result # <8>
|
||||
return clocked # <9>
|
||||
return decorate # <10>
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@clock() # <11>
|
||||
def snooze(seconds):
|
||||
time.sleep(seconds)
|
||||
|
||||
for i in range(3):
|
||||
snooze(.123)
|
||||
|
||||
# END CLOCKDECO_PARAM
|
||||
9
07-closure-deco/clockdeco_param_demo1.py
Normal file
9
07-closure-deco/clockdeco_param_demo1.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import time
|
||||
from clockdeco_param import clock
|
||||
|
||||
@clock('{name}: {elapsed}s')
|
||||
def snooze(seconds):
|
||||
time.sleep(seconds)
|
||||
|
||||
for i in range(3):
|
||||
snooze(.123)
|
||||
9
07-closure-deco/clockdeco_param_demo2.py
Normal file
9
07-closure-deco/clockdeco_param_demo2.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import time
|
||||
from clockdeco_param import clock
|
||||
|
||||
@clock('{name}({args}) dt={elapsed:0.3f}s')
|
||||
def snooze(seconds):
|
||||
time.sleep(seconds)
|
||||
|
||||
for i in range(3):
|
||||
snooze(.123)
|
||||
10
07-closure-deco/fibo_demo.py
Normal file
10
07-closure-deco/fibo_demo.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from clockdeco import clock
|
||||
|
||||
@clock
|
||||
def fibonacci(n):
|
||||
if n < 2:
|
||||
return n
|
||||
return fibonacci(n-2) + fibonacci(n-1)
|
||||
|
||||
if __name__=='__main__':
|
||||
print(fibonacci(6))
|
||||
13
07-closure-deco/fibo_demo_lru.py
Normal file
13
07-closure-deco/fibo_demo_lru.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import functools
|
||||
|
||||
from clockdeco import clock
|
||||
|
||||
@functools.lru_cache() # <1>
|
||||
@clock # <2>
|
||||
def fibonacci(n):
|
||||
if n < 2:
|
||||
return n
|
||||
return fibonacci(n-2) + fibonacci(n-1)
|
||||
|
||||
if __name__=='__main__':
|
||||
print(fibonacci(6))
|
||||
52
07-closure-deco/generic.py
Normal file
52
07-closure-deco/generic.py
Normal file
@@ -0,0 +1,52 @@
|
||||
r"""
|
||||
htmlize(): generic function example
|
||||
|
||||
# BEGIN HTMLIZE_DEMO
|
||||
|
||||
>>> htmlize({1, 2, 3}) # <1>
|
||||
'<pre>{1, 2, 3}</pre>'
|
||||
>>> htmlize(abs)
|
||||
'<pre><built-in function abs></pre>'
|
||||
>>> htmlize('Heimlich & Co.\n- a game') # <2>
|
||||
'<p>Heimlich & Co.<br>\n- a game</p>'
|
||||
>>> htmlize(42) # <3>
|
||||
'<pre>42 (0x2a)</pre>'
|
||||
>>> print(htmlize(['alpha', 66, {3, 2, 1}])) # <4>
|
||||
<ul>
|
||||
<li><p>alpha</p></li>
|
||||
<li><pre>66 (0x42)</pre></li>
|
||||
<li><pre>{1, 2, 3}</pre></li>
|
||||
</ul>
|
||||
|
||||
# END HTMLIZE_DEMO
|
||||
"""
|
||||
|
||||
# BEGIN HTMLIZE
|
||||
|
||||
from functools import singledispatch
|
||||
from collections import abc
|
||||
import numbers
|
||||
import html
|
||||
|
||||
@singledispatch # <1>
|
||||
def htmlize(obj):
|
||||
content = html.escape(repr(obj))
|
||||
return '<pre>{}</pre>'.format(content)
|
||||
|
||||
@htmlize.register(str) # <2>
|
||||
def _(text): # <3>
|
||||
content = html.escape(text).replace('\n', '<br>\n')
|
||||
return '<p>{0}</p>'.format(content)
|
||||
|
||||
@htmlize.register(numbers.Integral) # <4>
|
||||
def _(n):
|
||||
return '<pre>{0} (0x{0:x})</pre>'.format(n)
|
||||
|
||||
@htmlize.register(tuple) # <5>
|
||||
@htmlize.register(abc.MutableSequence)
|
||||
def _(seq):
|
||||
inner = '</li>\n<li>'.join(htmlize(item) for item in seq)
|
||||
return '<ul>\n<li>' + inner + '</li>\n</ul>'
|
||||
|
||||
# END HTMLIZE
|
||||
|
||||
124
07-closure-deco/global_x_local.rst
Normal file
124
07-closure-deco/global_x_local.rst
Normal file
@@ -0,0 +1,124 @@
|
||||
>>> def f1(a):
|
||||
... print(a)
|
||||
... print(b)
|
||||
...
|
||||
>>> f1(3)
|
||||
3
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File "<stdin>", line 3, in f1
|
||||
NameError: name 'b' is not defined
|
||||
>>> b = 6
|
||||
>>> f1(3)
|
||||
3
|
||||
6
|
||||
|
||||
>>> def f2(a):
|
||||
... print(a)
|
||||
... print(b)
|
||||
... b = 9
|
||||
...
|
||||
>>> f2(3)
|
||||
3
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File "<stdin>", line 3, in f2
|
||||
UnboundLocalError: local variable 'b' referenced before assignment
|
||||
|
||||
|
||||
# BEGIN F1_DIS
|
||||
>>> from dis import dis
|
||||
>>> dis(f1)
|
||||
2 0 LOAD_GLOBAL 0 (print) <1>
|
||||
3 LOAD_FAST 0 (a) <2>
|
||||
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
9 POP_TOP
|
||||
|
||||
3 10 LOAD_GLOBAL 0 (print)
|
||||
13 LOAD_GLOBAL 1 (b) <3>
|
||||
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
19 POP_TOP
|
||||
20 LOAD_CONST 0 (None)
|
||||
23 RETURN_VALUE
|
||||
# END F1_DIS
|
||||
# BEGIN F2_DIS
|
||||
>>> dis(f2)
|
||||
2 0 LOAD_GLOBAL 0 (print)
|
||||
3 LOAD_FAST 0 (a)
|
||||
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
9 POP_TOP
|
||||
|
||||
3 10 LOAD_GLOBAL 0 (print)
|
||||
13 LOAD_FAST 1 (b) <1>
|
||||
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
19 POP_TOP
|
||||
|
||||
4 20 LOAD_CONST 1 (9)
|
||||
23 STORE_FAST 1 (b)
|
||||
26 LOAD_CONST 0 (None)
|
||||
29 RETURN_VALUE
|
||||
# END F2_DIS
|
||||
>>> def f3(a):
|
||||
... global b
|
||||
... print(a)
|
||||
... print(b)
|
||||
... b = 9
|
||||
...
|
||||
>>> f3(3)
|
||||
3
|
||||
6
|
||||
>>> b
|
||||
9
|
||||
# BEGIN F3_DIS
|
||||
>>> dis(f3)
|
||||
3 0 LOAD_GLOBAL 0 (print)
|
||||
3 LOAD_FAST 0 (a)
|
||||
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
9 POP_TOP
|
||||
|
||||
4 10 LOAD_GLOBAL 0 (print)
|
||||
13 LOAD_GLOBAL 1 (b)
|
||||
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
19 POP_TOP
|
||||
|
||||
5 20 LOAD_CONST 1 (9)
|
||||
23 STORE_GLOBAL 1 (b)
|
||||
26 LOAD_CONST 0 (None)
|
||||
29 RETURN_VALUE
|
||||
# END F3_DIS
|
||||
|
||||
>>> def f4(b):
|
||||
... def f5(a):
|
||||
... nonlocal b
|
||||
... print(a)
|
||||
... print(b)
|
||||
... b = 7
|
||||
... return f5
|
||||
...
|
||||
>>> f5 = f4(8)
|
||||
>>> f5(2)
|
||||
2
|
||||
8
|
||||
>>> b
|
||||
9
|
||||
>>> f5(3)
|
||||
3
|
||||
7????
|
||||
|
||||
>>> dis(f5)
|
||||
4 0 LOAD_GLOBAL 0 (print)
|
||||
3 LOAD_FAST 0 (a)
|
||||
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
9 POP_TOP
|
||||
|
||||
5 10 LOAD_GLOBAL 0 (print)
|
||||
13 LOAD_DEREF 0 (b)
|
||||
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
|
||||
19 POP_TOP
|
||||
|
||||
6 20 LOAD_CONST 1 (7)
|
||||
23 STORE_DEREF 0 (b)
|
||||
26 LOAD_CONST 0 (None)
|
||||
29 RETURN_VALUE
|
||||
|
||||
|
||||
31
07-closure-deco/registration.py
Normal file
31
07-closure-deco/registration.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# BEGIN REGISTRATION
|
||||
|
||||
registry = [] # <1>
|
||||
|
||||
def register(func): # <2>
|
||||
print('running register(%s)' % func) # <3>
|
||||
registry.append(func) # <4>
|
||||
return func # <5>
|
||||
|
||||
@register # <6>
|
||||
def f1():
|
||||
print('running f1()')
|
||||
|
||||
@register
|
||||
def f2():
|
||||
print('running f2()')
|
||||
|
||||
def f3(): # <7>
|
||||
print('running f3()')
|
||||
|
||||
def main(): # <8>
|
||||
print('running main()')
|
||||
print('registry ->', registry)
|
||||
f1()
|
||||
f2()
|
||||
f3()
|
||||
|
||||
if __name__=='__main__':
|
||||
main() # <9>
|
||||
|
||||
# END REGISTRATION
|
||||
16
07-closure-deco/registration_abridged.py
Normal file
16
07-closure-deco/registration_abridged.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# BEGIN REGISTRATION_ABRIDGED
|
||||
registry = []
|
||||
|
||||
def register(func):
|
||||
print('running register(%s)' % func)
|
||||
registry.append(func)
|
||||
return func
|
||||
|
||||
@register
|
||||
def f1():
|
||||
print('running f1()')
|
||||
|
||||
print('running main()')
|
||||
print('registry ->', registry)
|
||||
f1()
|
||||
# END REGISTRATION_ABRIDGED
|
||||
28
07-closure-deco/registration_param.py
Normal file
28
07-closure-deco/registration_param.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# BEGIN REGISTRATION_PARAM
|
||||
|
||||
registry = set() # <1>
|
||||
|
||||
def register(active=True): # <2>
|
||||
def decorate(func): # <3>
|
||||
print('running register(active=%s)->decorate(%s)'
|
||||
% (active, func))
|
||||
if active: # <4>
|
||||
registry.add(func)
|
||||
else:
|
||||
registry.discard(func) # <5>
|
||||
|
||||
return func # <6>
|
||||
return decorate # <7>
|
||||
|
||||
@register(active=False) # <8>
|
||||
def f1():
|
||||
print('running f1()')
|
||||
|
||||
@register() # <9>
|
||||
def f2():
|
||||
print('running f2()')
|
||||
|
||||
def f3():
|
||||
print('running f3()')
|
||||
|
||||
# END REGISTRATION_PARAM
|
||||
113
07-closure-deco/strategy_best4.py
Normal file
113
07-closure-deco/strategy_best4.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# strategy_best4.py
|
||||
# Strategy pattern -- function-based implementation
|
||||
# selecting best promotion from list of functions
|
||||
# registered by a decorator
|
||||
|
||||
"""
|
||||
>>> joe = Customer('John Doe', 0)
|
||||
>>> ann = Customer('Ann Smith', 1100)
|
||||
>>> cart = [LineItem('banana', 4, .5),
|
||||
... LineItem('apple', 10, 1.5),
|
||||
... LineItem('watermellon', 5, 5.0)]
|
||||
>>> Order(joe, cart, fidelity)
|
||||
<Order total: 42.00 due: 42.00>
|
||||
>>> Order(ann, cart, fidelity)
|
||||
<Order total: 42.00 due: 39.90>
|
||||
>>> banana_cart = [LineItem('banana', 30, .5),
|
||||
... LineItem('apple', 10, 1.5)]
|
||||
>>> Order(joe, banana_cart, bulk_item)
|
||||
<Order total: 30.00 due: 28.50>
|
||||
>>> long_order = [LineItem(str(item_code), 1, 1.0)
|
||||
... for item_code in range(10)]
|
||||
>>> Order(joe, long_order, large_order)
|
||||
<Order total: 10.00 due: 9.30>
|
||||
>>> Order(joe, cart, large_order)
|
||||
<Order total: 42.00 due: 42.00>
|
||||
|
||||
# BEGIN STRATEGY_BEST_TESTS
|
||||
|
||||
>>> Order(joe, long_order, best_promo)
|
||||
<Order total: 10.00 due: 9.30>
|
||||
>>> Order(joe, banana_cart, best_promo)
|
||||
<Order total: 30.00 due: 28.50>
|
||||
>>> Order(ann, cart, best_promo)
|
||||
<Order total: 42.00 due: 39.90>
|
||||
|
||||
# END STRATEGY_BEST_TESTS
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
Customer = namedtuple('Customer', 'name fidelity')
|
||||
|
||||
|
||||
class LineItem:
|
||||
|
||||
def __init__(self, product, quantity, price):
|
||||
self.product = product
|
||||
self.quantity = quantity
|
||||
self.price = price
|
||||
|
||||
def total(self):
|
||||
return self.price * self.quantity
|
||||
|
||||
|
||||
class Order: # the Context
|
||||
|
||||
def __init__(self, customer, cart, promotion=None):
|
||||
self.customer = customer
|
||||
self.cart = list(cart)
|
||||
self.promotion = promotion
|
||||
|
||||
def total(self):
|
||||
if not hasattr(self, '__total'):
|
||||
self.__total = sum(item.total() for item in self.cart)
|
||||
return self.__total
|
||||
|
||||
def due(self):
|
||||
if self.promotion is None:
|
||||
discount = 0
|
||||
else:
|
||||
discount = self.promotion(self)
|
||||
return self.total() - discount
|
||||
|
||||
def __repr__(self):
|
||||
fmt = '<Order total: {:.2f} due: {:.2f}>'
|
||||
return fmt.format(self.total(), self.due())
|
||||
|
||||
# BEGIN STRATEGY_BEST4
|
||||
|
||||
promos = [] # <1>
|
||||
|
||||
def promotion(promo_func): # <2>
|
||||
promos.append(promo_func)
|
||||
return promo_func
|
||||
|
||||
@promotion # <3>
|
||||
def fidelity(order):
|
||||
"""5% discount for customers with 1000 or more fidelity points"""
|
||||
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
|
||||
|
||||
@promotion
|
||||
def bulk_item(order):
|
||||
"""10% discount for each LineItem with 20 or more units"""
|
||||
discount = 0
|
||||
for item in order.cart:
|
||||
if item.quantity >= 20:
|
||||
discount += item.total() * .1
|
||||
return discount
|
||||
|
||||
@promotion
|
||||
def large_order(order):
|
||||
"""7% discount for orders with 10 or more distinct items"""
|
||||
distinct_items = {item.product for item in order.cart}
|
||||
if len(distinct_items) >= 10:
|
||||
return order.total() * .07
|
||||
return 0
|
||||
|
||||
def best_promo(order): # <4>
|
||||
"""Select best discount available
|
||||
"""
|
||||
return max(promo(order) for promo in promos)
|
||||
|
||||
# END STRATEGY_BEST4
|
||||
Reference in New Issue
Block a user