2010-04-26 17 views
2

Je regardais un article sur le site Web de Peter Norvig, où il essaie de répondre à la question suivante (ce n'est pas ma question, btw) "Puis-je faire l'équivalent de (test?) en Python? "python fonction paramètre modèle d'évaluation

est ici l'une des options énumérées par lui,

def if_(test, result, alternative=None): 
    "If test is true, 'do' result, else alternative. 'Do' means call if callable." 
    if test: 
     if callable(result): result = result() 
     return result 
    else: 
     if callable(alternative): alternative = alternative() 
     return alternative 

Et voici un exemple d'utilisation.

>>> fact = lambda n: if_(n <= 1, 1, lambda: n * fact(n-1)) 
>>> fact(6) 
720 

Je comprends comment cela fonctionne (je pense), mais je viens de jouer avec le code, et a décidé de voir ce qui se passe quand je change le troisième argument dans la définition du « fait » ci-dessus pour n * fait (n-1), c'est-à-dire, le change en une expression non-appelable. En l'exécutant, l'interprète entre dans une boucle sans fin. J'ai une assez bonne idée de la raison pour laquelle cela se produit, c'est-à-dire que la fonction if_ renvoie la même expression que celle qu'elle reçoit. Mais quel est le type de cette expression? Qu'est-ce qui se passe exactement ici? Je ne cherche pas d'explication détaillée, mais juste quelques indications sur le modèle d'évaluation de python qui pourraient m'aider à comprendre.

Merci!

+2

Probablement sans rapport, mais vous pouvez simplement utiliser 'result if test else alternative'. – kennytm

Répondre

4

La raison pour laquelle la boucle se termine jamais quand vous changez fact à n * fact(n-1) est que n * fact(n-1) doit évaluer en premier (comme troisième argument à if). L'évaluer conduit à un autre appel au fact, à l'infini (puisqu'il n'y a plus de cas de base pour l'arrêter).

Auparavant, vous passiez un objet fonction (lambda), qui ne serait pas évalué jusqu'au corps de if, et son résultat serait vérifié via test. Ceci est connu (je crois) comme une évaluation avide, où les arguments de fonction sont évalués avant d'être transmis à la fonction. Dans un schéma d'évaluation paresseuse, les arguments ne seraient pas évalués avant d'avoir été utilisés dans le corps de la fonction.

+0

Si n <= 1 serait évalué correctement, la récursivité s'arrêterait à n = 1, renvoyant 1. – Krab

+1

'n <= 1' sera évalué, mais sa valeur n'est jamais vérifiée avant d'être dans le corps de la fonction. Quand il utilise une expression récursive au lieu d'un lambda comme troisième paramètre, le corps de la fonction n'est jamais atteint. – danben

+0

Je ne soutenais pas qu'il calcule n !, j'ai juste mal compris votre réponse. Maintenant, je le lis une fois de plus et je suis d'accord avec ça. – Krab