6
\$\begingroup\$

I wanted to implement a version of rambda's compose function in python. I also implemented some examples to show its working. However, I would like the community's input on my code:

These are the methods I use for testing

from functools import reduce, partial
import random
import math
def calcMean(iterable):
 return sum(iterable) / len(iterable)
def formatMean(mean):
 return round(float(mean), 2)
def adder(val, value):
 return val + value
def multiplier(val, value):
 return val * value
def isEven(val):
 return val % 2 == 0

The actual compose function

def compose(*fargs):
 def inner(arg):
 if not arg:
 raise ValueError("Invalid argument")
 if not all([callable(f) for f in fargs]):
 raise TypeError("Function is not callable")
 return reduce(lambda arg, func: func(arg), fargs, arg)
 return inner

The first exercise is something I came up with. In it I populate a list of length 10000 with random numbers from 0 to 10000, find the mean, round it to 2 decimal places, add 1 to it , then floor it and finally print out whether it is even or not.

if __name__ == '__main__':
 # Ex1
 rand_range = [random.randint(0, 10000) for x in range(0, 10000)]
 isRandIntEven = compose(calcMean, formatMean,
 partial(adder, value=1), math.floor.__call__, isEven)
 print(isRandIntEven(rand_range))

The second exercise is taken from rambda's compose page. I tried to see if I could replicate the example (theirs is much more elegant)

 # Ex2
 classyGreeting = lambda firstName, lastName: "The name's " + \
 lastName + ", " + firstName + " " + lastName
 yellGreeting = compose(partial(
 classyGreeting, "James".upper()), str.upper.__call__)
 print(yellGreeting("Bond"))

The last example is also taken from rambda's compose page

# Ex3
 print(compose(
 partial(multiplier, value=2),
 partial(adder, value=1),
 math.fabs)(-4))
Peilonrayz
44.4k7 gold badges80 silver badges157 bronze badges
asked Dec 4, 2017 at 23:22
\$\endgroup\$

1 Answer 1

8
\$\begingroup\$

Suggestions for compose:

def compose(*fargs):
 def inner(arg):
 if not arg:
 raise ValueError("Invalid argument")
 if not all([callable(f) for f in fargs]):
 raise TypeError("Function is not callable")
 return reduce(lambda arg, func: func(arg), fargs, arg)
 return inner
  1. if not arg: What's wrong with arg being falsey? Perhaps that's an acceptable input. Input validation should be designated to the functions being composed, which can raise their own errors.
  2. if not all([callable(f) ...: This line should be before def inner(args). It should be a single-time input validation to ensure that all given inputs in fargs are callable. Currently, it checks needless amounts of times (each inner call) and does not check immediately.
  3. if not all([callable(f) ...: You can use a generator expression instead of a list comprehension for this, slightly improving readability.

If both of these suggestions are implemented, your compose would look like:

def compose(*fargs):
 if not all(callable(f) for f in fargs):
 raise TypeError("Function is not callable")
 def inner(arg):
 return reduce(lambda arg, func: func(arg), fargs, arg)
 return inner

Please tell me if I have misunderstood your code.

answered Dec 5, 2017 at 4:37
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Yeah I understand your point with the functions that are being composed handling the case of arg being falsy. Oh didn't know writing all() like all(callable(f) .... turns it into a generator. Thanks for your input \$\endgroup\$ Commented Dec 5, 2017 at 6:24
  • 1
    \$\begingroup\$ @CasualCoder3 It doesn't turn the result of all(... into a generator, if that's what you mean. The "actual" call is all( (callable(f) for f in fargs) ), which passes the generator produces by (callable(f) for f in fargs) into all and evaluates to a boolean. (I call it the "actual" call because it explicitly shows the generator expression by including its ()'s. Python allows for omitting of ()'s around a generator expression if it's the sole argument to a function). \$\endgroup\$ Commented Dec 5, 2017 at 13:37

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.