17.3. plural.py, étape 2

Maintenant, nous allons ajouter un niveau d'abstraction. Nous avons commencé par définir une liste de règles : si telle condition est remplie, alors effectuer telle action, sinon passer à la règle suivante. Nous allons temporairement rendre plus complexe une partie du programme pour pouvoir en simplifier une autre.

Exemple 17.6. plural2.py


import re

def match_sxz(noun):                          
    return re.search('[sxz]$', noun)          

def apply_sxz(noun):                          
    return re.sub('$', 'es', noun)            

def match_h(noun):                            
    return re.search('[^aeioudgkprt]h$', noun)

def apply_h(noun):                            
    return re.sub('$', 'es', noun)            

def match_y(noun):                            
    return re.search('[^aeiou]y$', noun)      
        
def apply_y(noun):                            
    return re.sub('y$', 'ies', noun)          

def match_default(noun):                      
    return 1                                  
        
def apply_default(noun):                      
    return noun + 's'                         

rules = ((match_sxz, apply_sxz),
         (match_h, apply_h),
         (match_y, apply_y),
         (match_default, apply_default)
         )                                     1

def plural(noun):                             
    for matchesRule, applyRule in rules:       2
        if matchesRule(noun):                  3
            return applyRule(noun)             4
1 Cette version a l'air plus compliqué (en tout cas, elle est certainement plus longue), mais elle fait exactement la même chose : elle tente de reconnaître les mêmes quatre règles, dans l'ordre, et applique l'expression régulière appropriée lorsqu'un motif est reconnu. La différence est que chaque règle de recherche et de modification est définie dans sa propre fonction et que ces fonctions sont assemblées et assignées à la variable rules, qui est un tuple de tuples.
2 À l'aide d'une boucle for, nous pouvons appliquer deux règles à la fois (une de recherche et une de transformation) à partir du tuple rules. À la première itération de la boucle for loop, matchesRule référencera match_sxz et applyRule apply_sxz. À la seconde itération (si il y en a une), matchesRule référencera match_h et applyRule apply_h.
3 Rappelez vous que tout est objet en Python, y compris les fonctions. rules contient des fonctions, pas seulement des noms de fonctions. Lorsqu'elles sont assignées dans la boucle for, les variables matchesRule et applyRule sont des fonctions que vous pouvez appeler. Donc, à la première itération de la boucle for, cette ligne est l'équivalent d'un appel à matches_sxz(noun).
4 À la première itération de la boucle for, ceci est l'équivalent d'un appel à apply_sxz(noun), etc

Si ce niveau d'abstraction vous semble obscur, essayer de déplier les fonctions. Cette boucle for est l'équivalent de ce qui suit :

Exemple 17.7. La fonction plural dépliée


def plural(noun):
    if match_sxz(noun):
        return apply_sxz(noun)
    if match_h(noun):
        return apply_h(noun)
    if match_y(noun):
        return apply_y(noun)
    if match_default(noun):
        return apply_default(noun)

L'avantage ici est que la fonction plural est simplifiée. Elle prend une liste de règles, définie ailleurs, et les parcours de manière générique. On prend une règle de recherche, la chaîne est-elle reconnue ? Alors on appelle la règle de transformation. Les règles pourraient être définies à n'importe quel endroit et de n'importe quelle manière, la fonction plural ne s'en occupe pas.

Maintenant, est-ce que l'ajout de ce niveau d'abstraction en valait la peine ? Et bien, pas pour le moment. Considérons ce qu'il faudrait faire pour ajouter une nouvelle règle. Dans la version précédente, il aurait fallu ajouter une instruction if à la fonction plural. Dans cette version, il faut ajouter deux fonctions, match_foo et apply_foo, et mettre à jour la liste de règles rules pour spécifier entre quelles autres règles la nouvelle règle doit être appelée.

Cette étape n'est qu'une base pour la prochaine section, continuons donc.