Question

I wrote a function "rep" that takes a function f and takes n compositions of f. So rep(square,3) behaves like this: square(square(square(x))). And when I pass 3 into it, rep(square,3)(3)=6561.

There is no problem with my code, but I was wondering if there was a way to make it "prettier" (or shorter) without having to call another function or import anything. Thanks!

def compose1(f, g):
    """Return a function h, such that h(x) = f(g(x))."""
    def h(x):
        return f(g(x))
    return h

def rep(f,n):
    newfunc = f
    count=1
    while count < n:
        newfunc = compose1(f,newfunc)
        count+=1
    return newfunc
Était-ce utile?

La solution

If you're looking for speed, the for loop is clearly the way to go. But if you're looking for theoretical academic acceptance ;-), stick to terse functional idioms. Like:

def rep(f, n):
    return f if n == 1 else lambda x: f(rep(f, n-1)(x))

Autres conseils

def rep(f, n):
    def repeated(x):
        for i in xrange(n):
            x = f(x)
        return x
    return repeated

Using a for loop instead of while is shorter and more readable, and compose1 doesn't really need to be a separate function.

While I agree that repeated composition of the same function is best done with a loop, you could use *args to compose an arbitrary number of functions:

def identity(x):
    return x

def compose(*funcs):
    if funcs:
        rest = compose(*funcs[1:])
        return lambda x: funcs[0](rest(x))
    else:
        return identity

And in this case you would have:

def rep(f,n):
    funcs = (f,)*n # tuple with f repeated n times
    return compose(*funcs)

And as DSM kindly pointed out in the comments, you could remove the recursion like so:

def compose(*funcs):
    if not funcs:
        return identity
    else:
        def composed(x):
            for f in reversed(funcs):
                x = f(x)
            return x
        return composed

(also note that you can replace x with *args if you also want to support arbitrary arguments to the functions you're composing, but I left it at one argument since that's how you have it in the original problem)

Maybe someone will find this solution useful

Compose number of functions

from functools import reduce

def compose(*functions):
    return reduce(lambda x, y: (lambda arg: x(y(arg))), functions)

Use list comprehensions to generate list of functions

def multi(how_many, func):
    return compose(*[func for num in range(how_many)])

Usage

def square(x):
    return x * x

multi(3, square)(3) == 6561 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top