17.6. plural.py, étape 5

Nous avons extrait toute duplication de code et ajouter assez d'abstraction pour que les règles de pluriel des noms soient définies sous forme d'une liste de chaînes. La prochaine étape est logiquement de mettre ces chaînes dans un fichier séparé, pour qu'elles puissent être modifiées séparément du code qui les utilise.

D'abord, nous allons créer un fichier texte qui contient les règles. Ici, pas de structures de données sophistiquées, seulement des chaînes délimitées par des espaces (ou des tabulations) en trois colonnes. Nous l'appelons rules.en, «en» pour English. Ce sont les règles du pluriel des noms pour l'anglais. Nous pourrons ajouter d'autres fichiers de règles pour d'autre langues plus tard.

Exemple 17.15. rules.en

[sxz]$                  $               es
[^aeioudgkprt]h$        $               es
[^aeiou]y$              y$              ies
$                       $               s

Maintenant, voyons comment utiliser ce fichier de règles.

Exemple 17.16. plural5.py


import re
import string                                                                     

def buildRule((pattern, search, replace)):                                        
    return lambda word: re.search(pattern, word) and re.sub(search, replace, word) 1

def plural(noun, language='en'):                             2
    lines = file('rules.%s' % language).readlines()          3
    patterns = map(string.split, lines)                      4
    rules = map(buildRule, patterns)                         5
    for rule in rules:                                      
        result = rule(noun)                                  6
        if result: return result                            
1 Nous utilisons encore la technique des fermetures (construire dynamiquement une fonction qui utilise des variables définies à l'extérieur de cette fonction), mais maintenant nous avons combiné les fonctions de recherche et de transformation en une seule fonction (la raison de cette modification apparaîtra à la prochaine section). Cela nous permettra de faire la même chose qu'avec les deux fonctions, mais l'appel en sera différent, comme nous allons le voir.
2 Notre fonction plural prend maintenant un second argument optionnel, language, qui vaut en par défaut.
3 Nous utilisons l'argument language pour construire un nom de fichier, puis nous ouvrons ce fichier et copions sont contenu dans une liste. Si le langage est en, nous allons donc : ouvrir rules.en, le lire en entier, le segmenter à chaque retour à la ligne et retourner une liste. Chaque ligne du fichier est un élément de la liste.
4 Comme vous l'avez vu, chaque ligne du fichier contient en fait trois valeurs, séparées par des espaces (espaces ou tabulations ne font pas de différence). En appliquant la fonction string.split à la liste, nous créons une nouvelle liste dans laquelle chaque élément est un tuple de trois chaînes. Donc, une ligne comme [sxz]$ $ es sera segmentée en un tuple ('[sxz]$', '$', 'es'). Cela signifie que patterns contient une liste de tuples, comme nous l'avions fait à la main à l'étape 4.
5 Si patterns est une liste de tuples, alors rules sera une liste de fonctions créées dynamiquement par chaque appel à buildRule. L'appel à Calling buildRule(('[sxz]$', '$', 'es')) retourne une fonction qui prend un seul argument, word. Quand cette fonction retournée est appelée, elle exécute re.search('[sxz]$', word) et re.sub('$', 'es', word).
6 Comme nous construisons maintenant une fonction combinée de recherche et de transformation, nous devons l'appeler différemment. Nous appelons simplement cette fonction et si elle retourne quelque chose, c'est le pluriel du nom, si elle ne retourne rien (None), alors la règle ne s'applique pas et il faut essayer la règle suivante.

L'amélioration ici est que nous avons complètement séparé les règles de pluriel des noms dans un fichier externe. Non seulement ce fichier peut-être maintenu séparément du code, mais nous avons défini une règle de nommage de fichier grâce à laquelle la même fonction plural peut utiliser des fichiers de règles différents en fonction d'un argument language.

L'inconvénient est que nous lisons le fichier à chaque fois que nous appelons la fonction plural. Je pensais pouvoir finir ce livre sans utiliser la phrase «laissé en exercice au lecteur», mais c'est raté : le développement d'un mécanisme de cache pour les fichiers de règles qui se rafraîchisse automatiquement lorsque un fichier de règle est modifié entre deux appels est laissé en exercice au lecteur. Amusez-vous bien.