Chapitre 18. Ajustements des performances

Vous allez découvrir les merveilles de l'ajustement des performances. Ce n'est pas parce que Python est un langage interprété que vous ne devez pas vous soucier de l'optimisation du code. Mais ne vous en souciez pas trop.

18.1. Plonger

Il y a tellement de dangers liés à l'optimisation du code qu'il est difficile de savoir par quoi commencer.

Commençons par ceci :êtes-vous sûr que c'est vraiment nécessaire ? Votre code est-il si mauvais ? Cela vaut-il la peine de prendre le temps de l'ajuster ? Pendant la durée de vie de votre application, combien de temps sera passé à exécuter ce code, par rapport au temps passé à attendre un serveur de base de données distant ou à attendre une entrée utilisateur ?

Ensuite, êtes vous sûr que vous avez fini d'écrire le code ? L'optimisation prématurée, c'est comme mettre une cerise sur un gâteau à moitié cuit. Vous passez des heures ou des jours (ou plus) à optimiser les performances de votre code, simplement pour découvrir qu'il ne remplit pas sa tâche. C'est du temps perdu.

Cela ne veut pas dire que l'optimisation du code est inutile, mais vous devez considérer l'ensemble du système et décider si c'est la meilleure façon d'employer votre temps. Chaque minute que vous passez à optimiser votre code est une minute que vous n'utilisez pas pour ajouter des fonctionnalités, à écrire de la documentation, à jouer avec vos enfants ou à écrire des tests unitaires.

Ah oui, les tests unitaires. Cela va sans dire que vous devez avoir un jeu complet de tests unitaires avant de commencer les ajustements de performances. La dernière chose dont vous avez besoin est d'introduire des nouveaux bogues en modifiant vos algorithmes.

Ces mises en garde étant faites, examinons certaines techniques d'optimisation de code Python. Le code en question est une implémentation de l'algorithme Soundex. Soundex est une méthode utilisée au début du 20e siècle pour classer les patronymes pour le recensement aux Etats-Unis. Il groupe les noms dont la prononciation est semblable, de manière à ce que même si un nom était mal orthographié, il serait possible de le retrouver. Soundex est toujours utilisé pour la même raison, mais bien sûr nous utilisons maintenant des bases de données informatisées. La plupart des logiciels de base de données comprennent une fonction Soundex.

Il y a plusieurs variantes de l'algorithme Soundex. Voici celle que nous utiliserons dans ce chapitre.

  1. La première lettre du nom n'est pas modifiée
  2. Les lettres suivantes sont converties en chiffres, en fonction de la table suivante :
    • B, F, P et V deviennent 1
    • C, G, J, K, Q, S, X et Z deviennent 2.
    • D et T deviennent 3.
    • L devient 4.
    • M et N deviennent 5.
    • R devient 6.
  3. Les doublons consécutifs sont supprimés.
  4. Les 9 sont supprimés.
  5. Si le résultat fait moins de quatre caractères (la première lettre puis 3 chiffres), le résultat est complété de zéros.
  6. Si le résultat fait plus de quatre caractères, tout ce qui suit le quatrième caractère est supprimé.

Par exemple, mon nom, Pilgrim, devient P942695. Il n'y a pas de doublons consécutifs, donc rien à faire à cette étape. Nous enlevons ensuite les 9, ce qui laisse P4265. C'est trop long, nous supprimons les caractères surnuméraires, ce qui laisse P426.

Un autre exemple : Woo devient W99, qui devient W9, qui devient W, qui est complété de zéros pour faire W000.

Voici une première tentative de fonction Soundex

Exemple 18.1. soundex/stage1/soundex1a.py

Si vous ne l’avez pas déjà fait, vous pouvez télécharger cet exemple ainsi que les autres exemples du livre.


import string, re

charToSoundex = {"A": "9",
                 "B": "1",
                 "C": "2",
                 "D": "3",
                 "E": "9",
                 "F": "1",
                 "G": "2",
                 "H": "9",
                 "I": "9",
                 "J": "2",
                 "K": "2",
                 "L": "4",
                 "M": "5",
                 "N": "5",
                 "O": "9",
                 "P": "1",
                 "Q": "2",
                 "R": "6",
                 "S": "2",
                 "T": "3",
                 "U": "9",
                 "V": "1",
                 "W": "9",
                 "X": "2",
                 "Y": "9",
                 "Z": "2"}

def soundex(source):
    "convert string to Soundex equivalent"

    # Soundex requirements:
    # source string must be at least 1 character
    # and must consist entirely of letters
    allChars = string.uppercase + string.lowercase
    if not re.search('^[%s]+$' % allChars, source):
        return "0000"

    # Soundex algorithm:
    # 1. make first character uppercase
    source = source[0].upper() + source[1:]
    
    # 2. translate all other characters to Soundex digits
    digits = source[0]
    for s in source[1:]:
        s = s.upper()
        digits += charToSoundex[s]

    # 3. remove consecutive duplicates
    digits2 = digits[0]
    for d in digits[1:]:
        if digits2[-1] != d:
            digits2 += d
        
    # 4. remove all "9"s
    digits3 = re.sub('9', '', digits2)
    
    # 5. pad end with "0"s to 4 characters
    while len(digits3) < 4:
        digits3 += "0"
        
    # 6. return first 4 characters
    return digits3[:4]

if __name__ == '__main__':
    from timeit import Timer
    names = ('Woo', 'Pilgrim', 'Flingjingwaller')
    for name in names:
        statement = "soundex('%s')" % name
        t = Timer(statement, "from __main__ import soundex")
        print name.ljust(15), soundex(name), min(t.repeat())

Pour en savoir plus sur Soundex