Pipe Function in Python

In [1]:
from functools import reduce

This pipe function was inspired by this JavaScript-related tweet:

In [2]:
%%html
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Reduce is versatile:<br>const pipe = (...fns) =&gt; x =&gt; fns.reduce((v, f) =&gt; f(v), x);</p>&mdash; Eric Elliott (@_ericelliott) <a href="https://twitter.com/_ericelliott/status/1111737323518156802?ref_src=twsrc%5Etfw">March 29, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
In [3]:
def pipe(item, *funcs):
    r"""Combine the outputs an arbitrary number of functions.
    >>> attrs = (
    ...           'strip',
    ...           'upper',
    ...         )
    >>> funcs = (get_func(attr) for attr in attrs)
    >>> pipe('   hello, world   \t\n ', *(*funcs, exclaim))
    'HELLO, WORLD!'
    """
    
    def handler(value, f):
        return f(value)
    
    return reduce(handler, funcs, item)
In [4]:
def get_func(attr: str):
    """Return a function that returns the result of calling a callable attribute on an item.
    >>> get_func('upper')('hello')
    'HELLO'
    """
    
    def func(item):
        return getattr(item, attr)()
    
    return func
In [5]:
def exclaim(s: str):
    """Append an exclaimation point to the end of a string.
    >>> exclaim('hello')
    'hello!'
    """
    return f"{s}!"
In [6]:
if __name__ == "__main__":
    import doctest
    import sys
   
    sys.argv[-1] = "-v" # Make doctest.testmod verbose
    doctest.testmod()
Trying:
    exclaim('hello')
Expecting:
    'hello!'
ok
Trying:
    get_func('upper')('hello')
Expecting:
    'HELLO'
ok
Trying:
    attrs = (
              'strip',
              'upper',
            )
Expecting nothing
ok
Trying:
    funcs = (get_func(attr) for attr in attrs)
Expecting nothing
ok
Trying:
    pipe('   hello, world   \t\n ', *(*funcs, exclaim))
Expecting:
    'HELLO, WORLD!'
ok
1 items had no tests:
    __main__
3 items passed all tests:
   1 tests in __main__.exclaim
   1 tests in __main__.get_func
   3 tests in __main__.pipe
5 tests in 4 items.
5 passed and 0 failed.
Test passed.