<jupyter_start><jupyter_text>The functools.cache decorator implements memoization: 5 anoptimization technique that works by saving the results of previousinvocations of an expensive function, avoiding repeat computations onpreviously used arguments. Example 9-17. The very costly recursive way to compute the nth number inthe Fibonacci series<jupyter_code>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))<jupyter_output>[0.00000063s] fibonacci(0) -> 0
[0.00000081s] fibonacci(1) -> 1
[0.00010406s] fibonacci(2) -> 1
[0.00000060s] fibonacci(1) -> 1
[0.00000051s] fibonacci(0) -> 0
[0.00000064s] fibonacci(1) -> 1
[0.00006002s] fibonacci(2) -> 1
[0.00011270s] fibonacci(3) -> 2
[0.00027057s] fibonacci(4) -> 3
[0.00000044s] fibonacci(1) -> 1
[0.00000041s] fibonacci(0) -> 0
[0.00000067s] fibonacci(1) -> 1
[0.00006780s] fibonacci(2) -> 1
[0.00011756s] fibonacci(3) -> 2
[0.00000044s] fibonacci(0) -> 0
[0.00000053s] fibonacci(1) -> 1
[0.00005049s] fibonacci(2) -> 1
[0.00000047s] fibonacci(1) -> 1
[0.00000047s] fibonacci(0) -> 0
[0.00000056s] fibonacci(1) -> 1
[0.00005110s] fibonacci(2) -> 1
[0.00009983s] fibonacci(3) -> 2
[0.00019936s] fibonacci(4) -> 3
[0.00038036s] fibonacci(5) -> 5
[0.00070237s] fibonacci(6) -> 8
8<jupyter_text>Example 9-18. Faster implementation using caching<jupyter_code>import functools

from clockdeco import clock

@functools.cache
@clock
def fast_fibonacci(n):
    if n < 2:
        return n
    return fast_fibonacci(n -2) + fast_fibonacci(n -1)

if __name__ == '__main__':
    print(fast_fibonacci(6))<jupyter_output>[0.00000070s] fast_fibonacci(0) -> 0
[0.00000094s] fast_fibonacci(1) -> 1
[0.00013731s] fast_fibonacci(2) -> 1
[0.00000111s] fast_fibonacci(3) -> 2
[0.00019896s] fast_fibonacci(4) -> 3
[0.00000100s] fast_fibonacci(5) -> 5
[0.00025733s] fast_fibonacci(6) -> 8
8<jupyter_text>Using lru_cacheThe functools.cache decorator is actually a simple wrapper aroundthe older functools.lru_cache function, which is more flexible andcompatible with Python 3.8 and earlier versions. Single Dispatch Generic Functions Imagine we are creating a tool to debug web applications. We want togenerate HTML displays for different types of Python objects.<jupyter_code>import html

def htmlize(obj):
    content = html.escape(repr(obj))
    return f'<pre>{content}</pre>'

htmlize({1, 2, 3})
htmlize(abs)
htmlize('my name is Jalil.\n a game')<jupyter_output><empty_output><jupyter_text>Example 9-20. @singledispatch creates a <EMAIL> to bundle several functions into a genericfunction<jupyter_code>from functools import singledispatch
from collections import abc
import fractions 
import decimal
import html
import numbers

@singledispatch
def htmlize(obj: object) -> str:
    content = html.escape(repr(obj))
    return f'<pre>{content}</pre>'
@htmlize.register
def _(text: str) -> str:
    content = html.escape(text).replace('\n', '<br/>\n')
    return f'<p>{content}</p>'
@htmlize.register
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
def _(n: numbers.Integral) -> str:
    return f'<pre>{n} (0x{n:x})</pre>'
@htmlize.register
def _(n: bool) -> str:
    return f'<pre>{n}</pre>'
@htmlize.register(fractions.Fraction)
def _(x) -> str:
    frac = fractions.Fraction(x)
    return f'<pre>{frac.numerator}/{frac.denominator}</pre>'
@htmlize.register(decimal.Decimal)
@htmlize.register(float)
def _(x) -> str:
    frac = fractions.Fraction(x).limit_denominator()
    return f'<pre>{x} ({frac.numerator}/{frac.denominator})</pre>'<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1487426431246656, 'fraction_numerical': 0.10112359550561797, 'mean_word_length': 4.860501567398119, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 76, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '517071', 'license': 'MIT', 'n_tokens_mistral': 1679, 'n_tokens_neox': 1430, 'n_words': 344, 'path': 'chapter 9- Decorators and Closures/example 9-17-20-Decorators in the Standard Library.ipynb', 'repo_name': 'Jalilnkh/KartalOl-Fluent-Python-2022', 'size': '3754'}