# 10. Survol de la bibliothèque standard

## 10.1. Interface avec le système d’exploitation

Le module `os` propose des dizaines de fonctions pour interagir avec le système d’exploitation :

    >>> import os
    >>> os.getcwd()      # Return the current working directory
    'C:\\Python26'
    >>> os.chdir('/server/accesslogs')   # Change current working directory
    >>> os.system('mkdir today')   # Run the command mkdir in the system shell
    0

Veillez bien à utiliser `import os` plutôt que `from os import *`, sinon `os.open()` cache la primitive `open()` qui fonctionne différemment.

Les primitives `dir()` et `help()` sont des aides utiles lorsque vous travaillez en mode interactif avez des gros modules comme `os` :

    >>> import os
    >>> dir(os)
    <returns a list of all module functions>
    >>> help(os)
    <returns an extensive manual page created from the module's docstrings>

Pour la gestion des fichiers et dossiers, le module `shutil` expose une interface plus abstraite et plus facile à utiliser :

    >>> import shutil
    >>> shutil.copyfile('data.db', 'archive.db')
    >>> shutil.move('/build/executables', 'installdir')

## 10.2. Jokers sur les noms de fichiers

Le module `glob` fournit une fonction pour construire des listes de fichiers à partir de motifs :

    >>> import glob
    >>> glob.glob('*.py')
    ['primes.py', 'random.py', 'quote.py']

## 10.3. Paramètres passés en ligne de commande

Typiquement, les outils en ligne de commande ont besoin de lire les paramètres qui leur sont donnés. Ces paramètres sont stockés dans la variable `argv` du module `sys` sous la forme d’une liste. Par exemple, l’affichage suivant vient de l’exécution de `python demo.py one two three` depuis la ligne de commande :

    >>> import sys
    >>> print sys.argv
    ['demo.py', 'one', 'two', 'three']

Le module `getopt` analyse sys.argv en utilisant les conventions habituelles de la fonction Unix `getopt()`. Des outils d’analyse des paramètres de la ligne de commande plus flexibles et avancés sont disponibles dans le module `argparse`.

## 10.4. Redirection de la sortie d’erreur et fin d’exécution

Le module `sys` a aussi des attributs pour stdin, stdout et stderr. Ce dernier est utile pour émettre des messages d’avertissement ou d’erreur qui restent visibles même si stdout est redirigé :

    >>> sys.stderr.write('Warning, log file not found starting a new one\n')
    Warning, log file not found starting a new one

Le moyen le plus direct de terminer un script est d’utiliser `sys.exit()`.

## 10.5. Recherche de motifs dans les chaînes

Le module `re` fournit des outils basés sur les expressions rationnelles permettant des opérations complexes sur les chaînes. C’est une solution optimisée, utilisant une syntaxe concise, pour rechercher des motifs complexes ou effectuer des remplacements complexes dans les chaînes :

    >>> import re
    >>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
    ['foot', 'fell', 'fastest']
    >>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
    'cat in the hat'

Lorsque les opérations sont simples, il est préférable d’utiliser les méthodes des chaînes. Elles sont plus lisibles et plus faciles à déboguer :

    >>> 'tea for too'.replace('too', 'two')
    'tea for two'

## 10.6. Mathématiques

Le module `math` donne accès aux fonctions sur les nombres à virgule flottante (float en anglais) de la bibliothèque C :

    >>> import math
    >>> math.cos(math.pi / 4.0)
    0.70710678118654757
    >>> math.log(1024, 2)
    10.0

Le module `random` offre des outils pour faire des tirages aléatoires :

    >>> import random
    >>> random.choice(['apple', 'pear', 'banana'])
    'apple'
    >>> random.sample(xrange(100), 10)   # sampling without replacement
    [30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
    >>> random.random()    # random float
    0.17970987693706186
    >>> random.randrange(6)    # random integer chosen from range(6)
    4

## 10.7. Accès à internet

Il existe de nombreux modules pour accéder à internet et traiter les protocoles. Deux des plus simples sont `urllib2` pour récupérer des données depuis des URLs et `smtplib` pour envoyer des emails :

    >>> import urllib2
    >>> for line in urllib2.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'):
    ...     if 'EST' in line or 'EDT' in line:  # look for Eastern Time
    ...         print line

    <BR>Nov. 25, 09:43:32 PM EST

    >>> import smtplib
    >>> server = smtplib.SMTP('localhost')
    >>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
    ... """To: jcaesar@example.org
    ... From: soothsayer@example.org
    ...
    ... Beware the Ides of March.
    ... """)
    >>> server.quit()

Notez que le deuxième exemple a besoin d’un serveur mail tournant localement.

## 10.8. Dates et heures

Le module `datetime` propose des classes pour manipuler les dates et les heures de manière simple ou plus complexe. Bien que faire des calculs de dates et d’heures soit possible, la priorité de l’implémentation est mise sur l’extraction efficace des attributs pour le formatage et la manipulation. Le module gère aussi les objets dépendant des fuseaux horaires :

    >>> # dates are easily constructed and formatted
    >>> from datetime import date
    >>> now = date.today()
    >>> now
    datetime.date(2003, 12, 2)
    >>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
    '12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

    >>> # dates support calendar arithmetic
    >>> birthday = date(1964, 7, 31)
    >>> age = now - birthday
    >>> age.days
    14368

## 10.9. Compression de données

Les formats de compression et d’archivage les plus courants sont directements gérés par les modules comme : `zlib`, `gzip`, `bz2`, `zipfile` et `tarfile`.

    >>> import zlib
    >>> s = 'witch which has which witches wrist watch'
    >>> len(s)
    41
    >>> t = zlib.compress(s)
    >>> len(t)
    37
    >>> zlib.decompress(t)
    'witch which has which witches wrist watch'
    >>> zlib.crc32(s)
    226805979

## 10.10. Mesure des performances

Certains utilisateurs de Python sont très intéressés par les performances de différentes approches d’un même problème. Python propose un outil de mesure répondant simplement à ces questions.

Par exemple, pour échanger deux variables, il peut être tentant d’utiliser l’empaquetage et le dépaquetage de tuples plutôt que la méthode traditionnelle. Le module `timeit` montre rapidement le léger gain de performance obtenu :

    >>> from timeit import Timer
    >>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
    0.57535828626024577
    >>> Timer('a,b = b,a', 'a=1; b=2').timeit()
    0.54962537085770791

En opposition à `timeit` et sa granularité fine, `profile` et `pstats` fournissent des outils permettant d’identifier les parties les plus gourmandes en temps d’exécution dans des volumes de code plus grands.

## 10.11. Contrôle qualité

Une approche possible pour développer des application de très bonne qualité est d’écrire des tests pour chaque fonction au fur et à mesure de son développement, puis d’exécuter ces tests fréquemment lors du processus de développement.

Le module `doctest` cherche des tests dans les chaînes de documentation. Un test ressemble à un simple copier-coller d’un appel et son résultat depuis le mode interactif. Cela améliore la documentation en fournissant des exemples tout en prouvant qu’ils sont justes :

    def average(values):
        """Computes the arithmetic mean of a list of numbers.

        >>> print average([20, 30, 70])
        40.0
        """
        return sum(values, 0.0) / len(values)

    import doctest
    doctest.testmod()   # automatically validate the embedded tests

Le module `unittest` requiert plus d’efforts que le module `doctest` mais il permet de construire un jeu de tests plus complet que l’on fait évoluer dans un fichier séparé :

    import unittest

    class TestStatisticalFunctions(unittest.TestCase):

        def test_average(self):
            self.assertEqual(average([20, 30, 70]), 40.0)
            self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
            with self.assertRaises(ZeroDivisionError):
                average([])
            with self.assertRaises(TypeError):
                average(20, 30, 70)

    unittest.main()  # Calling from the command line invokes all tests

## 10.12. Piles fournies

Python adopte le principe des « piles fournies ». Vous pouvez le constater au travers des fonctionnalités évoluées et solides fournies par ses plus gros paquets. Par exemple :

- Les modules `xmlrpclib` et `SimpleXMLRPCServer` permettent d’appeler des fonctions à distance quasiment sans effort. En dépit du nom des modules, aucune connaissance du XML n’est nécessaire.
- Le paquet `email` est une bibliothèque pour gérer les messages electroniques, incluant les MIME et autre encodages basés sur la RFC 2822. Contrairement à `smtplib` et `poplib`, qui envoient et reçoivent des messages, le paquet email est une boite à outils pour construire, lire des structures de messages complexes (comprenant des pièces jointes), ou implémenter des encodages et protocoles.
- Les paquets `xml.dom` et `xml.sax` fournissent un moyen solide de parser ce format populaire. Aussi, le module `csv` peut lire et écrire dans un format de base de donnée commun. Ensemble, ces modules et paquets simplifient grandement l’échange de donnée entre les applications Python et les autres outils.
- L’internationalisation est possible grâce à de nombreux paquets tels que `gettext`, `locale` ou `codecs`.