Skip to content

Commit

Permalink
Merge pull request #250 from llllllllll/compose
Browse files Browse the repository at this point in the history
compose tweaks
  • Loading branch information
mrocklin committed Jul 21, 2015
2 parents 03cdb6c + b013610 commit 8ff64da
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 9 deletions.
2 changes: 2 additions & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ Bart van Merriënboer [@bartvm](https://github.com/ba
Nikolaos-Digenis Karagiannis [@digenis](https://github.com/digenis/)

[Antonio Lima](https://twitter.com/themiurgo) [@themiurgo](https://github.com/themiurgo/)

Joe Jevnik [@llllllllll](https://github.com/llllllllll)
48 changes: 39 additions & 9 deletions toolz/functoolz.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,23 +368,53 @@ class Compose(object):
See Also:
compose
"""
__slots__ = ['funcs']
__slots__ = 'first', 'funcs'

def __init__(self, *funcs):
self.funcs = funcs
def __init__(self, funcs):
funcs = tuple(reversed(funcs))
self.first = funcs[0]
self.funcs = funcs[1:]

def __call__(self, *args, **kwargs):
fns = list(reversed(self.funcs))
ret = fns[0](*args, **kwargs)
for f in fns[1:]:
ret = self.first(*args, **kwargs)
for f in self.funcs:
ret = f(ret)
return ret

def __getstate__(self):
return self.funcs
return self.first, self.funcs

def __setstate__(self, state):
self.funcs = tuple(state)
self.first, self.funcs = state

@property
def __doc__(self):
def composed_doc(*fs):
"""Generate a docstring for the composition of fs.
"""
if not fs:
# Argument name for the docstring.
return '*args, **kwargs'

return '{f}({g})'.format(f=fs[0].__name__, g=composed_doc(*fs[1:]))

try:
return (
'lambda *args, **kwargs: ' +
composed_doc(*reversed((self.first,) + self.funcs))
)
except AttributeError:
# One of our callables does not have a `__name__`, whatever.
return 'A composition of functions'

@property
def __name__(self):
try:
return '_of_'.join(
f.__name__ for f in reversed((self.first,) + self.funcs),
)
except AttributeError:
return type(self).__name__


def compose(*funcs):
Expand All @@ -409,7 +439,7 @@ def compose(*funcs):
if len(funcs) == 1:
return funcs[0]
else:
return Compose(*funcs)
return Compose(funcs)


def pipe(data, *funcs):
Expand Down
18 changes: 18 additions & 0 deletions toolz/tests/test_functoolz.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,24 @@ def f(a, b, c=10):

assert compose(str, inc, f)(1, 2, c=3) == '10'

# Define two functions with different names
def f(a):
return a

def g(a):
return a

composed = compose(f, g)
assert composed.__name__ == 'f_of_g'
assert composed.__doc__ == 'lambda *args, **kwargs: f(g(*args, **kwargs))'

# Create an object with no __name__.
h = object()

composed = compose(f, h)
assert composed.__name__ == 'Compose'
assert composed.__doc__ == 'A composition of functions'


def test_pipe():
assert pipe(1, inc) == 2
Expand Down

0 comments on commit 8ff64da

Please sign in to comment.