2017-08-26 5 views
1

Supposons qu'il existe des fonctions de transformation utiles, par exemple random_spelling_error, que nous aimerions appliquer n fois.Python moyen de ré-appliquer une fonction à sa propre sortie n fois?

Ma solution temporaire ressemble à ceci:

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!") 

est-il un moyen intégré ou autrement mieux faire?

Il n'est pas nécessaire de gérer des arguments de longueur variable ou des arguments, mais cela pourrait être le cas. La fonction sera appelée à l'échelle, mais les valeurs de n seront faibles et la taille de l'argument et la valeur de retour seront faibles.

On pourrait appeler cela reduce mais ce nom était bien sûr pris pour une fonction qui peut faire cela et trop beaucoup plus, et a été retiré en Python 3. Voici Guido's argument:

Donc, dans mon esprit, l'applicabilité de reduce() est à peu près limitée à opérateurs associatifs, et dans tous les autres cas, il est préférable d'écrire explicitement .

+0

Voir les solutions R: https://stackoverflow.com/questions/29237136/relooping-a-function-over-its-own-output –

+3

Je ne pense pas qu'il y ait quelque chose de mal ou de "non-pythonique" à propos de votre boucle. Oui, peut-être que vous pourriez le faire en une ligne au lieu de trois, mais pour quoi faire? Il est immédiatement clair ce qu'il est censé faire, ce qui en fait _very_ pythonic à mon humble avis. –

+1

@tobias_k Je suis d'accord qu'il est lisible (et efficace) tel quel, je me demande simplement s'il y a une convention ou si j'ai dupliqué quelque chose, parce que la tâche semble très ordinaire. –

Répondre

0

certains récursion comme, de toute évidence pas toujours 'mieux'

def reapply(n, fn, arg): 
    if n: 
     arg = reapply(n-1, fn, fn(arg)) 
    return arg 


reapply(1, lambda x: x**2, 2) 
Out[161]: 4 

reapply(2, lambda x: x**2, 2) 
Out[162]: 16 
+1

Pourrait être raccourci comme 'return reapply (...) si n else arg', mais à mon humble avis ni plus clair ni meilleur (limite de récursivité?). –

1

reduce est toujours disponible en python 3 en utilisant le module functools. Je ne sais pas vraiment que c'est plus pythonique, mais voici comment vous pouvez y parvenir en une ligne:

from functools import reduce 

def reapply(n, fn, arg): 
    return reduce(lambda x, _: fn(x), range(n), arg) 
+1

Merci, la boucle est plus lisible et enregistre l'import donc en pratique je le choisirais dessus, mais c'est une bonne réponse pour ceux qui sont curieux de savoir comment cela se ferait avec 'reduce'. –

0

Débarrassez-vous de la fonction personnalisée complètement, vous essayez de compresser deux lignes lisibles dans une confusion appel de fonction. Lequel pensez-vous est plus facile à lire et à comprendre, votre chemin:

foo = reapply(3, random_spelling_error, foo) 

Ou simple boucle for qui est une ligne de plus:

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

Mise à jour: Selon votre commentaire

Supposons qu'il existe plusieurs fonctions de transformation que je souhaite appliquer.

Pourquoi ne pas essayer quelque chose comme ceci:

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

Ou si vous avez besoin différent quantité de répétitions pour différentes fonctions, essayez de créer une liste de tuples:

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

for modifier, count in modifiers: 
    for _ in range(count): 
     foo = modifier(foo) 
+0

Supposons qu'il existe de nombreuses fonctions de transformation que je souhaite appliquer. (Il y a.) Il pourrait aussi y avoir d'autres raisons pour que la fonction soit une variable. –

+0

@ A.M.Bittlingmayer Voir la mise à jour. Je ne pense pas que vous devriez forcer les futurs développeurs (même futurs) à aller lire ce que fait "réappliquer" quand tout peut être fait dans quelques lignes de Python. –

+0

Et si jamais vous avez vraiment besoin d'une fonction, alors votre chemin est le meilleur, gardez-le simple. Mais je ne pense pas que vous devriez utiliser une fonction ici. –