Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic way to re-apply a function to its own output n times?

Assume there are some useful transformation functions, for example random_spelling_error, that we would like to apply n times.

My temporary solution looks like this:

def reapply(n, fn, arg):
    for i in range(n):
        arg = fn(arg)
    return arg


reapply(3, random_spelling_error, "This is not a test!")

Is there a built-in or otherwise better way to do this?

It need not handle variable lengths args or keyword args, but it could. The function will be called at scale, but the values of n will be low and the size of the argument and return value will be small.

We could call this reduce but that name was of course taken for a function that can do this and too much more, and was removed in Python 3. Here is Guido's argument:

So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it's better to write out the accumulation loop explicitly.

like image 625
Adam Bittlingmayer Avatar asked Sep 12 '25 20:09

Adam Bittlingmayer


2 Answers

reduce is still available in python 3 using the functools module. I don't really know that it's any more pythonic, but here's how you could achieve it in one line:

from functools import reduce

def reapply(n, fn, arg):
    return reduce(lambda x, _: fn(x), range(n), arg)
like image 82
DBrowne Avatar answered Sep 15 '25 09:09

DBrowne


Get rid of the custom function completely, you're trying to compress two readable lines into one confusing function call. Which one do you think is easier to read and understand, your way:

foo = reapply(3, random_spelling_error, foo)

Or a simple for loop that's one more line:

for _ in range(3):
    foo = random_spelling_error(foo)

Update: According to your comment

Let's assume that there are many transformation functions I may want to apply.

Why not try something like this:

modifiers = (random_spelling_error, another_function, apply_this_too)
for modifier in modifiers:
    for _ in range(3):
        foo = modifier(foo)

Or if you need different amount of repeats for different functions, try creating a list of tuples:

modifiers = [
    (random_spelling_error, 5),
    (another_function, 3),
    ...
]

for modifier, count in modifiers:
    for _ in range(count):
        foo = modifier(foo)
like image 23
Markus Meskanen Avatar answered Sep 15 '25 09:09

Markus Meskanen