forked from colonelpanic/dotfiles
Finish compose.py.
This commit is contained in:
parent
6cd1921102
commit
d6d5adef71
@ -1,30 +1,57 @@
|
||||
import collections
|
||||
import functools
|
||||
|
||||
|
||||
def compose2(f, g):
|
||||
return lambda x: f(g(x))
|
||||
from partialable import n_partialable
|
||||
|
||||
|
||||
def compose(*functions):
|
||||
return reduce(compose2, functions)
|
||||
def _compose2(f, g):
|
||||
return lambda *args, **kwargs: f(g(*args, **kwargs))
|
||||
|
||||
|
||||
def extract_args(function):
|
||||
@n_partialable(evaluation_checker=n_partialable.count_evaluation_checker(2))
|
||||
def compose_with_joiner(joiner, *functions):
|
||||
return reduce(joiner, functions)
|
||||
|
||||
|
||||
compose_one_arg = compose_with_joiner(_compose2)
|
||||
|
||||
|
||||
compose = compose_with_joiner(lambda f, g: _compose2(make_single_arity(f),
|
||||
force_args_return(g)))
|
||||
|
||||
|
||||
def make_single_arity(function):
|
||||
@functools.wraps(function)
|
||||
def wrapped(args):
|
||||
return function(*args)
|
||||
return wrapped
|
||||
|
||||
|
||||
def extract_kwargs(function):
|
||||
def kwargs_make_single_arity(function):
|
||||
@functools.wraps(function)
|
||||
def wrapped(kwargs):
|
||||
return function(**kwargs)
|
||||
return wrapped
|
||||
|
||||
|
||||
def extract_args_kwargs(function):
|
||||
def args_kwargs_make_single_arity(function):
|
||||
@functools.wraps(function)
|
||||
def wrapped((args, kwargs)):
|
||||
return function(*args, **kwargs)
|
||||
return wrapped
|
||||
|
||||
|
||||
def force_args_return(function):
|
||||
@functools.wraps(function)
|
||||
def wrapped(*args, **kwargs):
|
||||
value = function(*args, **kwargs)
|
||||
if not isinstance(value, collections.Iterable):
|
||||
value = (value,)
|
||||
return value
|
||||
return wrapped
|
||||
|
||||
|
||||
def tee(*functions):
|
||||
def wrapped(*args, **kwargs):
|
||||
return tuple(function(*args, **kwargs) for function in functions)
|
||||
return wrapped
|
||||
|
12
resources/python/compose_test.py
Normal file
12
resources/python/compose_test.py
Normal file
@ -0,0 +1,12 @@
|
||||
import compose
|
||||
|
||||
|
||||
def test_compose_handles_multiple_argument_output_and_non_iterable_output():
|
||||
assert compose.compose(lambda x: x*2,
|
||||
lambda x, y: x + y,
|
||||
lambda x, y, z: (2*(x - y), z))(1, 2, 3) == 2
|
||||
|
||||
|
||||
def test_tee():
|
||||
assert compose.compose(lambda x, y: x + y,
|
||||
compose.tee(lambda x: x + 1, lambda x: x - 1))(2) == 4
|
@ -4,10 +4,13 @@ import inspect
|
||||
class n_partialable(object):
|
||||
|
||||
@staticmethod
|
||||
def arity_evaluation_checker(function):
|
||||
def arity_evaluation_checker(function, is_method=False):
|
||||
is_class = inspect.isclass(function)
|
||||
if is_class:
|
||||
function = function.__init__
|
||||
function_info = inspect.getargspec(function)
|
||||
function_args = function_info.args
|
||||
if inspect.isclass(function):
|
||||
if is_class or is_method:
|
||||
# This is to handle the fact that self will get passed in automatically.
|
||||
function_args = function_args[1:]
|
||||
def evaluation_checker(*args, **kwargs):
|
||||
@ -21,10 +24,17 @@ class n_partialable(object):
|
||||
return not needed_args or kwarg_keys.issuperset(needed_args)
|
||||
return evaluation_checker
|
||||
|
||||
def __init__(self, function, evaluation_checker=None, args=None, kwargs=None):
|
||||
@staticmethod
|
||||
def count_evaluation_checker(count):
|
||||
def function(*args, **kwargs):
|
||||
return len(args) >= count
|
||||
return function
|
||||
|
||||
def __init__(self, function, evaluation_checker=None, args=None, kwargs=None,
|
||||
is_method=False):
|
||||
self.function = function
|
||||
self.evaluation_checker = (evaluation_checker or
|
||||
self.arity_evaluation_checker(function))
|
||||
self.arity_evaluation_checker(function, is_method))
|
||||
self.args = args or ()
|
||||
self.kwargs = kwargs or {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user