Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bpo-35853: More higher order function combinators in functools #11699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions Doc/library/functools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,65 @@ The :mod:`functools` module defines the following functions:
See :func:`itertools.accumulate` for an iterator that yields all intermediate
values.


.. function:: identity(x)

Returns its argument unchanged. This function can be used in situations
in which a default function argument is required.

>>> from itertools import cycle
>>> from functools import identity
>>> def negate(x): return -x
...
>>> def inverse_second(iterable):
... return map(lambda t: t[0](t[1]), zip(cycle([identity, negate]), iterable))
...
>>> print(list(inverse_second([1,2,3,4,5,6,7,8,9])))
[1, -2, 3, -4, 5, -6, 7, -8, 9]


.. function:: compose(f1[, f2[, f3[...]]])

Return a new *function* **f**. The resulting function **f** will be a so called
threaded computation. A threaded computation will use the return value of the
first function as the input value of the second function and the return value
of the second function will become the input o the third function until no
more functions are left. The last return value will be the final return value
of **f**. In summary ``compose(f1,f2,f3)(x) == f3(f2(f1(x)))``.

This is also called a pipeline, because it follows the same logic as the
pipe character of the UNIX shell `echo x | f1 | f2 | f3`.

>>> from functools import compose, partial
>>> rectify_data = compose(
... lambda s: s.split('\n'),
... partial(filter, lambda s: len(s)>0),
... partial(map, lambda s: s.lower()),
... lambda ss: '\n'.join(ss)
... )
>>> data = "Line1\nLiNe2\n\n\n\nlINE3"
>>> rectify_data(data)
'line1\nline2\nline3'


.. function:: sequence(x, f1[, f2[, f3[...]]])

Apply the argument *x* to the composition of the functions. This is a
helper function and equivalent to ``compose(f1,f2,f3)(x)``.

>>> from functools import sequence, partial
>>> data = "Line1\nLiNe2\n\n\n\nlINE3"
>>> rectified_data = sequence(
... data,
... lambda s: s.split('\n'),
... partial(filter, lambda s: len(s)>0),
... partial(map, lambda s: s.lower()),
... lambda ss: '\n'.join(ss)
... )
>>> rectified_data
'line1\nline2\nline3'


.. decorator:: singledispatch

Transform a function into a :term:`single-dispatch <single
Expand Down
33 changes: 32 additions & 1 deletion Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial',
'partialmethod', 'singledispatch', 'singledispatchmethod']
'partialmethod', 'identity', 'compose', 'sequence',
'singledispatch', 'singledispatchmethod']

from abc import get_cache_token
from collections import namedtuple
Expand Down Expand Up @@ -430,6 +431,36 @@ def _unwrap_partial(func):
func = func.func
return func


################################################################################
### Higher order function combinator primitives
################################################################################

def identity(x):
"""The identity functions simply returns its argument"""
return x


def compose(f, *func_list):
"""Compose a list of functions into one new function. The resulting
function will thread the computation results through all of its component
functions, i.e. the return value of the previous function will be the
input to the next function. For example, for f = compose(f1, f2), f(x)
would be equivalent to f2(f1(x)).
"""
def helper(*args, **kwargs):
return reduce(lambda x, f: f(x), func_list, f(*args, **kwargs))
return helper


def sequence(x, f, *func_list):
"""Thread the given input argument through all provided functions,
whereupon the return value of a previous function becomes the input value
to the next function and the overall value of the sequence will be the
result of the last function. For example, sequence(x, f1, f2) == f2(f1(x)).
"""
return compose(f, *func_list)(x)

################################################################################
### LRU Cache function decorator
################################################################################
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Higher order functions are functions which can take other functions as arguments and have functions as return value. Higher order functions allow the creation of new functions out of existing ones and support a functional programming style. The *functools* module now contains more higher order function combinators.