Finish compose.py.

This commit is contained in:
Ivan Malison 2014-09-11 22:52:45 -07:00
parent 6cd1921102
commit d6d5adef71
3 changed files with 61 additions and 12 deletions

View File

@ -1,30 +1,57 @@
import collections
import functools import functools
from partialable import n_partialable
def compose2(f, g):
return lambda x: f(g(x))
def compose(*functions): def _compose2(f, g):
return reduce(compose2, functions) 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) @functools.wraps(function)
def wrapped(args): def wrapped(args):
return function(*args) return function(*args)
return wrapped return wrapped
def extract_kwargs(function): def kwargs_make_single_arity(function):
@functools.wraps(function) @functools.wraps(function)
def wrapped(kwargs): def wrapped(kwargs):
return function(**kwargs) return function(**kwargs)
return wrapped return wrapped
def extract_args_kwargs(function): def args_kwargs_make_single_arity(function):
@functools.wraps(function) @functools.wraps(function)
def wrapped((args, kwargs)): def wrapped((args, kwargs)):
return function(*args, **kwargs) return function(*args, **kwargs)
return wrapped 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

View 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

View File

@ -4,10 +4,13 @@ import inspect
class n_partialable(object): class n_partialable(object):
@staticmethod @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_info = inspect.getargspec(function)
function_args = function_info.args 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. # This is to handle the fact that self will get passed in automatically.
function_args = function_args[1:] function_args = function_args[1:]
def evaluation_checker(*args, **kwargs): def evaluation_checker(*args, **kwargs):
@ -21,10 +24,17 @@ class n_partialable(object):
return not needed_args or kwarg_keys.issuperset(needed_args) return not needed_args or kwarg_keys.issuperset(needed_args)
return evaluation_checker 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.function = function
self.evaluation_checker = (evaluation_checker or self.evaluation_checker = (evaluation_checker or
self.arity_evaluation_checker(function)) self.arity_evaluation_checker(function, is_method))
self.args = args or () self.args = args or ()
self.kwargs = kwargs or {} self.kwargs = kwargs or {}