ch08, 09, 10: example files

This commit is contained in:
Luciano Ramalho
2020-06-11 14:58:15 -03:00
parent 42861b64d8
commit bf4a2be8b9
111 changed files with 4707 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
Sample code for Chapter 8 - "Closures and decorators"
From the book "Fluent Python, Second Edition" by Luciano Ramalho (O'Reilly, 2020)
http://shop.oreilly.com/product/0636920273196.do

View 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

View 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)

View File

@@ -0,0 +1,21 @@
import time
import functools
def clock(func):
@functools.wraps(func)
def clocked(*args, **kwargs):
t0 = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - t0
name = func.__name__
arg_lst = []
if args:
arg_lst.append(', '.join(repr(arg) for arg in args))
if kwargs:
pairs = [f'{k}={v!r}' for k, v in kwargs.items()]
arg_lst.append(', '.join(pairs))
arg_str = ', '.join(arg_lst)
print(f'[{elapsed:0.8f}s] {name}({arg_str}) -> {result!r}')
return result
return clocked

View File

@@ -0,0 +1,13 @@
import time
def clock(func):
def clocked(*args): # <1>
t0 = time.perf_counter()
result = func(*args) # <2>
elapsed = time.perf_counter() - t0
name = func.__name__
arg_str = ', '.join(repr(arg) for arg in args)
print(f'[{elapsed:0.8f}s] {name}({arg_str}) -> {result!r}')
return result
return clocked # <3>

View File

@@ -0,0 +1,44 @@
# clockdeco_class.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
"""
# tag::CLOCKDECO_CLS[]
import time
DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args}) -> {result}'
class clock: # <1>
def __init__(self, fmt=DEFAULT_FMT): # <2>
self.fmt = fmt
def __call__(self, func): # <3>
def clocked(*_args):
t0 = time.perf_counter()
_result = func(*_args) # <4>
elapsed = time.perf_counter() - t0
name = func.__name__
args = ', '.join(repr(arg) for arg in _args)
result = repr(_result)
print(self.fmt.format(**locals()))
return _result
return clocked
# end::CLOCKDECO_CLS[]
if __name__ == '__main__':
@clock()
def snooze(seconds):
time.sleep(seconds)
for i in range(3):
snooze(.123)

View File

@@ -0,0 +1,19 @@
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))

View 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
"""
# tag::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.perf_counter()
_result = func(*_args) # <4>
elapsed = time.perf_counter() - 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[]

View 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)

View 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)

View File

@@ -0,0 +1,17 @@
from clockdeco import clock
import fibo_demo
import fibo_demo_lru
@clock
def demo1():
fibo_demo.fibonacci(30)
@clock
def demo2():
fibo_demo_lru.fibonacci(30)
demo1()
demo2()

View File

@@ -0,0 +1,12 @@
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))

View File

@@ -0,0 +1,15 @@
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))

View 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
# tag::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[]
# tag::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
# tag::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

View File

@@ -0,0 +1,76 @@
r"""
htmlize(): generic function example
# tag::HTMLIZE_DEMO[]
>>> htmlize({1, 2, 3}) # <1>
'<pre>{1, 2, 3}</pre>'
>>> htmlize(abs)
'<pre>&lt;built-in function abs&gt;</pre>'
>>> htmlize('Heimlich & Co.\n- a game') # <2>
'<p>Heimlich &amp; 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>
>>> htmlize(True) # <5>
'<pre>True</pre>'
>>> htmlize(fractions.Fraction(2, 3)) # <6>
'<pre>2/3</pre>'
>>> htmlize(2/3) # <7>
'<pre>0.6666666666666666 (2/3)</pre>'
>>> htmlize(decimal.Decimal('0.02380952'))
'<pre>0.02380952 (1/42)</pre>'
# end::HTMLIZE_DEMO[]
"""
# tag::HTMLIZE[]
from functools import singledispatch
from collections import abc
import fractions
import decimal
import html
import numbers
@singledispatch # <1>
def htmlize(obj: object) -> str:
content = html.escape(repr(obj))
return f'<pre>{content}</pre>'
@htmlize.register # <2>
def _(text: str) -> str: # <3>
content = html.escape(text).replace('\n', '<br>\n')
return f'<p>{content}</p>'
@htmlize.register # <4>
def _(seq: abc.Sequence) -> str:
inner = '</li>\n<li>'.join(htmlize(item) for item in seq)
return '<ul>\n<li>' + inner + '</li>\n</ul>'
@htmlize.register # <5>
def _(n: numbers.Integral) -> str:
return f'<pre>{n} (0x{n:x})</pre>'
@htmlize.register # <6>
def _(n: bool) -> str:
return f'<pre>{n}</pre>'
@htmlize.register(fractions.Fraction) # <7>
def _(x) -> str:
frac = fractions.Fraction(x)
return f'<pre>{frac.numerator}/{frac.denominator}</pre>'
@htmlize.register(decimal.Decimal) # <8>
@htmlize.register(float)
def _(x) -> str:
frac = fractions.Fraction(x).limit_denominator()
return f'<pre>{x} ({frac.numerator}/{frac.denominator})</pre>'
# end::HTMLIZE[]

View File

@@ -0,0 +1,31 @@
# tag::REGISTRATION[]
registry = [] # <1>
def register(func): # <2>
print(f'running register({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[]

View File

@@ -0,0 +1,16 @@
# tag::REGISTRATION_ABRIDGED[]
registry = []
def register(func):
print(f'running register({func})')
registry.append(func)
return func
@register
def f1():
print('running f1()')
print('running main()')
print('registry ->', registry)
f1()
# end::REGISTRATION_ABRIDGED[]

View File

@@ -0,0 +1,28 @@
# tag::REGISTRATION_PARAM[]
registry = set() # <1>
def register(active=True): # <2>
def decorate(func): # <3>
print('running register'
f'(active={active})->decorate({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[]

View File

@@ -0,0 +1,36 @@
def first(f):
print(f'apply first({f.__name__})')
def inner1st(n):
result = f(n)
print(f'inner1({n}): called {f.__name__}({n}) -> {result}')
return result
return inner1st
def second(f):
print(f'apply second({f.__name__})')
def inner2nd(n):
result = f(n)
print(f'inner2({n}): called {f.__name__}({n}) -> {result}')
return result
return inner2nd
@first
@second
def double(n):
return n * 2
print(double(3))
def double_(n):
return n * 2
double_ = first(second(double_))
print(double_(3))