ruk·si

🐍 Python
functools

Updated at 2018-11-19 19:49

Standard library functools module contains a lot of useful functional tools, like the name implies.

reduce applies a function to first pair, then pushes that result and the next item to the function etc.

import numbers
from functools import reduce

def add(x: numbers.Integral, y: numbers.Integral) -> numbers.Integral:
    return x + y

assert reduce(add, [2, 4, 8], 0) == 14

partial allows freezing arguments. This actually means creating "partial functions".

from unicodedata import normalize
from functools import partial

nfc = partial(normalize, 'NFC')
assert nfc('café') == nfc('cafe\u0301')

lru_cache allows caching function returns. Especially good in deterministic heavy computation and fetching data over network. Note that each set of parameters is cached as a separate entity.

from functools import lru_cache

@lru_cache()
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 2) + fibonacci(n - 1)

# normally these would take over a minute all together
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465
assert fibonacci(35) == 9227465

singledispatch allows each module to contribute to the overall solution by type. Used to avoid long if/elif/elif chains. @singledispatch marks the base function that will be called if nothing else matches. Note that singledispatch definitions can even be in separate modules.

import html
from functools import singledispatch
from collections import abc

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

@htmlize.register(str)
def _(text):
    content = html.escape(text).replace('\n', '<br />\n')
    return f'<p>{content}</p>'

# when possible, use specialized types to handle types e.g.
# numbers.Integral > int
# abc.MutableSequence > list
# this creates more versatile and future proof code

@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(sequence):
    inner = f'</li>\n<li>'.join(htmlize(item) for item in sequence)
    return f'<ul>\n<li>{inner}</li>\n</ul>'

assert htmlize({1, 2, 3}) == '<pre>{1, 2, 3}</pre>'
assert htmlize('hello') == '<p>hello</p>'
assert htmlize(123) == '<pre>123</pre>'
assert htmlize((1, 2)) == '<ul>\n<li><pre>1</pre></li>\n<li><pre>2</pre></li>\n</ul>'
assert htmlize([1, 2]) == '<ul>\n<li><pre>1</pre></li>\n<li><pre>2</pre></li>\n</ul>'

Source

  • Python Tricks The Book, Dan Bader
  • Fluent Python, Luciano Ramalho