Function composition in Python3 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))
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



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.
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.
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.