This document is for an old version of Python that is no longer supported. You should upgrade and read the Python documentation for the current stable release.

# FAQ sur la bibliothèque et les extension

Sommaire

- FAQ sur la bibliothèque et les extension

  - Questions générales sur la bibliothèque

    - Comment puis-je trouver un module ou une application pour exécuter la tâche X?

    - Où se situe le fichier source math.py (socket.py, regex.py, etc.) ?

    - Comment rendre un script Python exécutable sous Unix ?

    - Existe-t’il un module curse ou termcap en Python ?

    - Existe-t’il un équivalent à la fonction C `onexit()` en Python ?

    - Pourquoi mes gestionnaires de signaux ne fonctionnent-t’ils pas ?

  - Tâches fréquentes

    - Comment tester un programme ou un composant Python ?

    - Comment générer la documentation à partir des docstrings ?

    - Comment détecter qu’une touche est pressée ?

  - Fils d’exécution

    - Comment programmer avec des fils d’exécution ?

    - Aucun de mes fils ne semble s’exécuter : pourquoi ?

    - Comment découper et répartir une tâche au sein d’un ensemble de fils d’exécutions ?

    - Quels types de mutations sur des variables globales sont compatibles avec les programmes à fils d’exécution multiples ? sécurisé ?

    - Pourquoi ne pas se débarrasser du verrou global de l’interpréteur ?

  - Les entrées/sorties

    - Comment supprimer un fichier ? (et autres questions sur les fichiers…)

    - Comment copier un fichier ?

    - Comment lire (ou écrire) des données binaires ?

    - Il me semble impossible d’utiliser `os.read()` sur un tube créé avec `os.popen()` ; pourquoi ?

    - How do I run a subprocess with pipes connected to both input and output?

    - Comment accéder au port de transmission en série (RS-232) ?

    - Pourquoi fermer sys.stdout, sys.stdin, sys.stderr ne les ferme pas réellement ?

  - Programmation réseau et Internet

    - Quels sont les outils Python dédiés à la Toile ?

    - Comment reproduire un envoi de formulaire CGI (METHOD=POST) ?

    - Quel module utiliser pour générer du HTML ?

    - Comment envoyer un courriel avec un script Python ?

    - Comment éviter de bloquer dans la méthode `connect()` d’un connecteur réseau ?

  - Bases de données

    - Existe-t’il des modules Python pour s’interfacer avec des bases de données ?

    - Comment implémenter la persistance d’objets en Python ?

    - Why is cPickle so slow?

    - If my program crashes with a bsddb (or anydbm) database open, it gets corrupted. How come?

    - I tried to open Berkeley DB file, but bsddb produces bsddb.error: (22, “Invalid argument”). Help! How can I restore my data?

  - Mathématiques et calcul numérique

    - Comment générer des nombres aléatoires en Python ?

## Questions générales sur la bibliothèque

### Comment puis-je trouver un module ou une application pour exécuter la tâche X?

Regardez si la bibliothèque standard contient un module approprié (avec l’expérience, vous connaitrez le contenu de la bibliothèque standard et pourrez sauter cette étape).

For third-party packages, search the Python Package Index or try Google or another Web search engine. Searching for « Python » plus a keyword or two for your topic of interest will usually find something helpful.

### Où se situe le fichier source math.py (socket.py, regex.py, etc.) ?

Si vous ne parvenez pas à trouver le fichier source d’un module, c’est peut-être parce que celui-ci est un module natif ou bien un module implémenté en C, C++, ou autre langage compilé, qui est chargé dynamiquement. Dans ce cas, vous ne possédez peut-être pas le fichier source ou celui-ci est en réalité stocké quelque part dans un dossier de fichiers source C (qui ne sera pas dans le chemin Python), comme par exemple `mathmodule.c`.

Il y a (au moins) trois types de modules dans Python

1. modules écrits en Python (.py) ;

2. modules écrits en C et chargés dynamiquement (.dll, .pyd, .so, .sl, .etc) ;

3. les modules écrits en C et liés à l’interpréteur ; pour obtenir leur liste, entrez :

       import sys
       print sys.builtin_module_names

### Comment rendre un script Python exécutable sous Unix ?

Deux conditions doivent être remplies : les droits d’accès au fichier doivent permettre son exécution et la première ligne du script doit commencer par `#!` suivi du chemin vers l’interpréteur Python.

La première condition est remplie en exécutant `chmod +x scriptfile` ou `chmod 755 scriptfile`.

Il y a plusieurs façons de remplir la seconde. La plus simple consiste à écrire au tout début du fichier

    #!/usr/local/bin/python

en utilisant le chemin de l’interpréteur Python sur votre machine.

Pour rendre ce script indépendant de la localisation de l’interpréteur Python, il faut utiliser le programme env. La ligne ci-dessous fonctionne sur la quasi-totalité des dérivés de Unix, à condition que l’interpréteur Python soit dans un dossier référencé dans la variable `PATH` de l’utilisateur :

    #!/usr/bin/env python

Ne faites pas ceci pour des scripts CGI. La variable `PATH` des scripts CGI est souvent très succincte, il faut par conséquent préciser le chemin absolu réel de l’interpréteur.

Occasionally, a user’s environment is so full that the /usr/bin/env program fails; or there’s no env program at all. In that case, you can try the following hack (due to Alex Rezinsky):

    #! /bin/sh
    """:"
    exec python $0 ${1+"$@"}
    """

Le léger inconvénient est que cela définit la variable __doc__ du script. Cependant, il est possible de corriger cela en ajoutant

    __doc__ = """...Whatever..."""

### Existe-t’il un module curse ou termcap en Python ?

For Unix variants the standard Python source distribution comes with a curses module in the Modules subdirectory, though it’s not compiled by default. (Note that this is not available in the Windows distribution – there is no curses module for Windows.)

Le module `curses` comprend les fonctionnalités de base de curses et beaucoup de fonctionnalités supplémentaires provenant de ncurses et de SYSV curses comme la couleur, la gestion des ensembles de caractères alternatifs, la prise en charge du pavé tactile et de la souris. Cela implique que le module n’est pas compatible avec des systèmes d’exploitation qui n’ont que le curses de BSD mais, de nos jours, de tels systèmes d’exploitation ne semblent plus exister ou être maintenus.

Pour Windows : utilisez le module consolelib.

### Existe-t’il un équivalent à la fonction C `onexit()` en Python ?

Le module `atexit` fournit une fonction d’enregistrement similaire à la fonction C `onexit()`.

### Pourquoi mes gestionnaires de signaux ne fonctionnent-t’ils pas ?

Le problème le plus courant est d’appeler le gestionnaire de signaux avec les mauvais arguments. Un gestionnaire est appelé de la façon suivante

    handler(signum, frame)

donc il doit être déclaré avec deux paramètres :

    def handler(signum, frame):
        ...

## Tâches fréquentes

### Comment tester un programme ou un composant Python ?

Python fournit deux cadriciels de test. Le module `doctest` cherche des exemples dans les docstrings d’un module et les exécute. Il compare alors la sortie avec la sortie attendue, telle que définie dans la docstring.

Le module `unittest` est un cadriciel un peu plus élaboré basé sur les cadriciels de test de Java et de Smalltalk.

Pour rendre le test plus aisé, il est nécessaire de bien découper le code d’un programme. Votre programme doit avoir la quasi-totalité des fonctionnalités dans des fonctions ou des classes — et ceci a parfois l’avantage aussi plaisant qu’inattendu de rendre le programme plus rapide, les accès aux variables locales étant en effet plus rapides que les accès aux variables globales. De plus le programme doit éviter au maximum de manipuler des variables globales, car ceci rend le test beaucoup plus difficile.

La « logique générale » d’un programme devrait être aussi simple que

    if __name__ == "__main__":
        main_logic()

à la fin du module principal du programme.

Une fois que la logique du programme est implémentée par un ensemble de fonctions et de comportements de classes, il faut écrire des fonctions de test qui vont éprouver cette logique. À chaque module, il est possible d’associer une suite de tests qui joue de manière automatique un ensemble de tests. Au premier abord, il semble qu’il faille fournir un effort conséquent, mais comme Python est un langage concis et flexible, c’est surprenamment aisé. Écrire simultanément le code « de production » et les fonctions de test associées rend le développement plus agréable et plus amusant, car ceci permet de trouver des bogues, voire des défauts de conception, plus facilement.

Les « modules auxiliaires » qui n’ont pas vocation à être le module principal du programme peuvent inclure un test pour se vérifier eux-mêmes.

    if __name__ == "__main__":
        self_test()

Les programmes qui interagissent avec des interfaces externes complexes peuvent être testés même quand ces interfaces ne sont pas disponibles, en utilisant des interfaces « simulacres » implémentées en Python.

### Comment générer la documentation à partir des docstrings ?

Le module `pydoc` peut générer du HTML à partir des docstrings du code source Python. Il est aussi possible de documenter une API uniquement à partir des docstrings à l’aide de epydoc. Sphinx peut également inclure du contenu provenant de docstrings.

### Comment détecter qu’une touche est pressée ?

For Unix variants there are several solutions. It’s straightforward to do this using curses, but curses is a fairly large module to learn. Here’s a solution without curses:

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()

    oldterm = termios.tcgetattr(fd)
    newattr = termios.tcgetattr(fd)
    newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
    termios.tcsetattr(fd, termios.TCSANOW, newattr)

    oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

    try:
        while 1:
            try:
                c = sys.stdin.read(1)
                print "Got character", repr(c)
            except IOError: pass
    finally:
        termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
        fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

You need the `termios` and the `fcntl` module for any of this to work, and I’ve only tried it on Linux, though it should work elsewhere. In this code, characters are read and printed one at a time.

`termios.tcsetattr()` turns off stdin’s echoing and disables canonical mode. `fcntl.fnctl()` is used to obtain stdin’s file descriptor flags and modify them for non-blocking mode. Since reading stdin when it is empty results in an `IOError`, this error is caught and ignored.

## Fils d’exécution

### Comment programmer avec des fils d’exécution ?

Be sure to use the `threading` module and not the `thread` module. The `threading` module builds convenient abstractions on top of the low-level primitives provided by the `thread` module.

Un ensemble de diapositives issues du didacticiel de Aahz sur les fils d’exécution est disponible à http://www.pythoncraft.com/OSCON2001/.

### Aucun de mes fils ne semble s’exécuter : pourquoi ?

Dès que le fil d’exécution principal se termine, tous les fils sont tués. Le fil principal s’exécute trop rapidement, sans laisser le temps aux autres fils de faire quoi que ce soit.

Une correction simple consiste à ajouter un temps d’attente suffisamment long à la fin du programme pour que tous les fils puissent se terminer :

    import threading, time

    def thread_task(name, n):
        for i in range(n): print name, i

    for i in range(10):
        T = threading.Thread(target=thread_task, args=(str(i), i))
        T.start()

    time.sleep(10) # <----------------------------!

Mais à présent, sur beaucoup de plates-formes, les fils ne s’exécutent pas en parallèle, mais semblent s’exécuter de manière séquentielle, l’un après l’autre ! En réalité, l’ordonnanceur de fils du système d’exploitation ne démarre pas de nouveau fil avant que le précédent ne soit bloqué.

Une correction simple consiste à ajouter un petit temps d’attente au début de la fonction :

    def thread_task(name, n):
        time.sleep(0.001) # <---------------------!
        for i in range(n): print name, i

    for i in range(10):
        T = threading.Thread(target=thread_task, args=(str(i), i))
        T.start()

    time.sleep(10)

Instead of trying to guess a good delay value for `time.sleep()`, it’s better to use some kind of semaphore mechanism. One idea is to use the `Queue` module to create a queue object, let each thread append a token to the queue when it finishes, and let the main thread read as many tokens from the queue as there are threads.

### Comment découper et répartir une tâche au sein d’un ensemble de fils d’exécutions ?

Use the `Queue` module to create a queue containing a list of jobs. The `Queue` class maintains a list of objects and has a `.put(obj)` method that adds items to the queue and a `.get()` method to return them. The class will take care of the locking necessary to ensure that each job is handed out exactly once.

Voici un exemple trivial :

    import threading, Queue, time

    # The worker thread gets jobs off the queue.  When the queue is empty, it
    # assumes there will be no more work and exits.
    # (Realistically workers will run until terminated.)
    def worker():
        print 'Running worker'
        time.sleep(0.1)
        while True:
            try:
                arg = q.get(block=False)
            except Queue.Empty:
                print 'Worker', threading.currentThread(),
                print 'queue empty'
                break
            else:
                print 'Worker', threading.currentThread(),
                print 'running with argument', arg
                time.sleep(0.5)

    # Create queue
    q = Queue.Queue()

    # Start a pool of 5 workers
    for i in range(5):
        t = threading.Thread(target=worker, name='worker %i' % (i+1))
        t.start()

    # Begin adding work to the queue
    for i in range(50):
        q.put(i)

    # Give threads time to run
    print 'Main thread sleeping'
    time.sleep(5)

Quand celui-ci est exécuté, il produit la sortie suivante :

    Running worker
    Running worker
    Running worker
    Running worker
    Running worker
    Main thread sleeping
    Worker <Thread(worker 1, started)> running with argument 0
    Worker <Thread(worker 2, started)> running with argument 1
    Worker <Thread(worker 3, started)> running with argument 2
    Worker <Thread(worker 4, started)> running with argument 3
    Worker <Thread(worker 5, started)> running with argument 4
    Worker <Thread(worker 1, started)> running with argument 5
    ...

Consult the module’s documentation for more details; the `Queue` class provides a featureful interface.

### Quels types de mutations sur des variables globales sont compatibles avec les programmes à fils d’exécution multiples ? sécurisé ?

A global interpreter lock (GIL) is used internally to ensure that only one thread runs in the Python VM at a time. In general, Python offers to switch among threads only between bytecode instructions; how frequently it switches can be set via `sys.setcheckinterval()`. Each bytecode instruction and therefore all the C implementation code reached from each instruction is therefore atomic from the point of view of a Python program.

En théorie, cela veut dire qu’un décompte exact nécessite une connaissance parfaite de l’implémentation de la MVP. En pratique, cela veut dire que les opérations sur des variables partagées de type natif (les entier, les listes, les dictionnaires etc.) qui « semblent atomiques » le sont réellement.

Par exemple, les opérations suivantes sont toutes atomiques (L, L1 et L2 sont des listes, D, D1 et D2 sont des dictionnaires, x et y sont des objets, i et j des entiers) :

    L.append(x)
    L1.extend(L2)
    x = L[i]
    x = L.pop()
    L1[i:j] = L2
    L.sort()
    x = y
    x.field = y
    D[x] = y
    D1.update(D2)
    D.keys()

Les suivantes ne le sont pas :

    i = i+1
    L.append(L[-1])
    L[i] = L[j]
    D[x] = D[x] + 1

Les opérations qui remplacent d’autres objets peuvent invoquer la méthode `__del__()` de ces objets quand leur compteur de référence passe à zéro, et cela peut avoir de l’impact. C’est tout particulièrement vrai pour les des changements massifs sur des dictionnaires ou des listes. En cas de doute, il vaut mieux utiliser un mutex.

### Pourquoi ne pas se débarrasser du verrou global de l’interpréteur ?

Le verrou global de l’interpréteur (GIL) est souvent vu comme un obstacle au déploiement de code Python sur des serveurs puissants avec de nombreux processeurs, car un programme Python à fils d’exécutions multiples n’utilise en réalité qu’un seul processeur. Presque tout le code Python ne peut en effet être exécuté qu’avec le GIL acquis.

Back in the days of Python 1.5, Greg Stein actually implemented a comprehensive patch set (the « free threading » patches) that removed the GIL and replaced it with fine-grained locking. Unfortunately, even on Windows (where locks are very efficient) this ran ordinary Python code about twice as slow as the interpreter using the GIL. On Linux the performance loss was even worse because pthread locks aren’t as efficient.

Since then, the idea of getting rid of the GIL has occasionally come up but nobody has found a way to deal with the expected slowdown, and users who don’t use threads would not be happy if their code ran at half the speed. Greg’s free threading patch set has not been kept up-to-date for later Python versions.

This doesn’t mean that you can’t make good use of Python on multi-CPU machines! You just have to be creative with dividing the work up between multiple processes rather than multiple threads. Judicious use of C extensions will also help; if you use a C extension to perform a time-consuming task, the extension can release the GIL while the thread of execution is in the C code and allow other threads to get some work done.

On a déjà proposé de restreindre le GIL par interpréteur, et non plus d’être complétement global ; les interpréteurs ne seraient plus en mesure de partager des objets. Malheureusement, cela n’a pas beaucoup de chance non plus d’arriver. Cela nécessiterait un travail considérable, car la façon dont beaucoup d’objets sont implémentés rend leur état global. Par exemple, les entiers et les chaînes de caractères courts sont mis en cache ; ces caches devraient être déplacés au niveau de l’interpréteur. D’autres objets ont leur propre liste de suppression, ces listes devraient être déplacées au niveau de l’interpréteur et ainsi de suite.

C’est une tâche sans fin, car les extensions tierces ont le même problème, et il est probable que les extensions tierces soient développées plus vite qu’il ne soit possible de les corriger pour les faire stocker leur état au niveau de l’interpréteur et non plus au niveau global.

Et enfin, quel intérêt y-a t’il à avoir plusieurs interpréteurs qui ne partagent pas d’état, par rapport à faire tourner chaque interpréteur dans un processus différent ?

## Les entrées/sorties

### Comment supprimer un fichier ? (et autres questions sur les fichiers…)

Use `os.remove(filename)` or `os.unlink(filename)`; for documentation, see the `os` module. The two functions are identical; `unlink()` is simply the name of the Unix system call for this function.

Utilisez `os.rmdir()` pour supprimer un dossier et `os.mkdir()` pour en créer un nouveau. `os.makedirs(chemin)` crée les dossiers intermédiaires de `chemin` qui n’existent pas et `os.removedirs(chemin)` supprime les dossiers intermédiaires si ceux-ci sont vides. Pour supprimer une arborescence et tout son contenu, utilisez `shutil.rmtree()`.

`os.rename(ancien_chemin, nouveau_chemin)` permet de renommer un fichier.

To truncate a file, open it using `f = open(filename, "r+")`, and use `f.truncate(offset)`; offset defaults to the current seek position. There’s also `os.ftruncate(fd, offset)` for files opened with `os.open()`, where fd is the file descriptor (a small integer).

Le module `shutil` propose aussi un grand nombre de fonctions pour effectuer des opérations sur des fichiers comme `copyfile()`, `copytree()` et `rmtree()`.

### Comment copier un fichier ?

Le module `shutil` fournit la fonction `copyfile()`. Sous MacOS 9, celle-ci ne copie pas le clonage de ressources ni les informations du chercheur.

### Comment lire (ou écrire) des données binaires ?

Pour lire ou écrire des formats de données complexes en binaire, il est recommandé d’utiliser le module `struct`. Celui-ci permet de convertir une chaîne de caractères qui contient des données binaires, souvent des nombres, en objets Python, et vice-versa.

Par exemple, le code suivant lit, depuis un fichier, deux entiers codés sur 2 octets et un entier codé sur 4 octets, en format gros-boutiste :

    import struct

    f = open(filename, "rb")  # Open in binary mode for portability
    s = f.read(8)
    x, y, z = struct.unpack(">hhl", s)

« > » dans la chaîne de formatage indique que la donnée doit être lue en mode gros-boutiste, la lettre « h » indique un entier court (2 octets) et la lettre « l » indique un entier long (4 octets).

Pour une donnée plus régulière (p. ex. une liste homogène d’entiers ou de nombres à virgule flottante), il est possible d’utiliser le module `array`.

### Il me semble impossible d’utiliser `os.read()` sur un tube créé avec `os.popen()` ; pourquoi ?

`os.read()` est une fonction de bas niveau qui prend en paramètre un descripteur de fichier — un entier court qui représente le fichier ouvert. `os.popen()` crée un objet fichier de haut niveau, du même type que celui renvoyé par la fonction native `open()`. Par conséquent, pour lire n octets d’un tube p créé avec `os.popen()`, il faut utiliser `p.read(n)`.

### How do I run a subprocess with pipes connected to both input and output?

Use the `popen2` module. For example:

    import popen2
    fromchild, tochild = popen2.popen2("command")
    tochild.write("input\n")
    tochild.flush()
    output = fromchild.readline()

Warning: in general it is unwise to do this because you can easily cause a deadlock where your process is blocked waiting for output from the child while the child is blocked waiting for input from you. This can be caused by the parent expecting the child to output more text than it does or by data being stuck in stdio buffers due to lack of flushing. The Python parent can of course explicitly flush the data it sends to the child before it reads any output, but if the child is a naive C program it may have been written to never explicitly flush its output, even if it is interactive, since flushing is normally automatic.

Note that a deadlock is also possible if you use `popen3()` to read stdout and stderr. If one of the two is too large for the internal buffer (increasing the buffer size does not help) and you `read()` the other one first, there is a deadlock, too.

Note on a bug in popen2: unless your program calls `wait()` or `waitpid()`, finished child processes are never removed, and eventually calls to popen2 will fail because of a limit on the number of child processes. Calling `os.waitpid()` with the `os.WNOHANG` option can prevent this; a good place to insert such a call would be before calling `popen2` again.

In many cases, all you really need is to run some data through a command and get the result back. Unless the amount of data is very large, the easiest way to do this is to write it to a temporary file and run the command with that temporary file as input. The standard module `tempfile` exports a `mktemp()` function to generate unique temporary file names.

    import tempfile
    import os

    class Popen3:
        """
        This is a deadlock-safe version of popen that returns
        an object with errorlevel, out (a string) and err (a string).
        (capturestderr may not work under windows.)
        Example: print Popen3('grep spam','\n\nhere spam\n\n').out
        """
        def __init__(self,command,input=None,capturestderr=None):
            outfile=tempfile.mktemp()
            command="( %s ) > %s" % (command,outfile)
            if input:
                infile=tempfile.mktemp()
                open(infile,"w").write(input)
                command=command+" <"+infile
            if capturestderr:
                errfile=tempfile.mktemp()
                command=command+" 2>"+errfile
            self.errorlevel=os.system(command) >> 8
            self.out=open(outfile,"r").read()
            os.remove(outfile)
            if input:
                os.remove(infile)
            if capturestderr:
                self.err=open(errfile,"r").read()
                os.remove(errfile)

Note that many interactive programs (e.g. vi) don’t work well with pipes substituted for standard input and output. You will have to use pseudo ttys (« ptys ») instead of pipes. Or you can use a Python interface to Don Libes” « expect » library. A Python extension that interfaces to expect is called « expy » and available from http://expectpy.sourceforge.net. A pure Python solution that works like expect is pexpect.

### Comment accéder au port de transmission en série (RS-232) ?

Pour Win32, POSIX (Linux, BSD, etc.) et Jython :

> http://pyserial.sourceforge.net

Pour Unix, référez-vous à une publication sur Usenet de Mitch Chapman :

> https://groups.google.com/groups?selm=34A04430.CF9@ohioee.com

### Pourquoi fermer sys.stdout, sys.stdin, sys.stderr ne les ferme pas réellement ?

Python file objects are a high-level layer of abstraction on top of C streams, which in turn are a medium-level layer of abstraction on top of (among other things) low-level C file descriptors.

For most file objects you create in Python via the built-in `file` constructor, `f.close()` marks the Python file object as being closed from Python’s point of view, and also arranges to close the underlying C stream. This also happens automatically in `f`’s destructor, when `f` becomes garbage.

But stdin, stdout and stderr are treated specially by Python, because of the special status also given to them by C. Running `sys.stdout.close()` marks the Python-level file object as being closed, but does not close the associated C stream.

To close the underlying C stream for one of these three, you should first be sure that’s what you really want to do (e.g., you may confuse extension modules trying to do I/O). If it is, use os.close:

    os.close(0)   # close C's stdin stream
    os.close(1)   # close C's stdout stream
    os.close(2)   # close C's stderr stream

## Programmation réseau et Internet

### Quels sont les outils Python dédiés à la Toile ?

Référez-vous aux chapitres intitulés Gestion des protocoles internet et Traitement des données provenant d’Internet dans le manuel de référence de la bibliothèque. Python a de nombreux modules pour construire des applications de Toile côté client comme côté serveur.

Un résumé des cadriciels disponibles est maintenu par Paul Boddie à l’adresse https://wiki.python.org/moin/WebProgramming.

Cameron Laird maintient un ensemble intéressant d’articles sur les technologies Python dédiées à la Toile à l’adresse http://phaseit.net/claird/comp.lang.python/web_python.

### Comment reproduire un envoi de formulaire CGI (METHOD=POST) ?

J’aimerais récupérer la page de retour d’un envoi de formulaire sur la Toile. Existe-t’il déjà du code qui pourrait m’aider à le faire facilement ?

Yes. Here’s a simple example that uses httplib:

    #!/usr/local/bin/python

    import httplib, sys, time

    # build the query string
    qs = "First=Josephine&MI=Q&Last=Public"

    # connect and send the server a path
    httpobj = httplib.HTTP('www.some-server.out-there', 80)
    httpobj.putrequest('POST', '/cgi-bin/some-cgi-script')
    # now generate the rest of the HTTP headers...
    httpobj.putheader('Accept', '*/*')
    httpobj.putheader('Connection', 'Keep-Alive')
    httpobj.putheader('Content-type', 'application/x-www-form-urlencoded')
    httpobj.putheader('Content-length', '%d' % len(qs))
    httpobj.endheaders()
    httpobj.send(qs)
    # find out what the server said in response...
    reply, msg, hdrs = httpobj.getreply()
    if reply != 200:
        sys.stdout.write(httpobj.getfile().read())

Note that in general for percent-encoded POST operations, query strings must be quoted using `urllib.urlencode()`. For example, to send `name=Guy Steele, Jr.`:

    >>> import urllib
    >>> urllib.urlencode({'name': 'Guy Steele, Jr.'})
    'name=Guy+Steele%2C+Jr.'

### Quel module utiliser pour générer du HTML ?

La page wiki de la programmation Toile (en anglais) répertorie un ensemble de liens pertinents.

### Comment envoyer un courriel avec un script Python ?

Utilisez le module `smtplib` de la bibliothèque standard.

Voici un exemple très simple d’un envoyeur de courriel qui l’utilise. Cette méthode fonctionne sur tous les serveurs qui implémentent SMTP.

    import sys, smtplib

    fromaddr = raw_input("From: ")
    toaddrs  = raw_input("To: ").split(',')
    print "Enter message, end with ^D:"
    msg = ''
    while True:
        line = sys.stdin.readline()
        if not line:
            break
        msg += line

    # The actual mail send
    server = smtplib.SMTP('localhost')
    server.sendmail(fromaddr, toaddrs, msg)
    server.quit()

Sous Unix, il est possible d’utiliser sendmail. La localisation de l’exécutable sendmail dépend du système ; cela peut-être `/usr/lib/sendmail` ou `/usr/sbin/sendmail`, la page de manuel de sendmail peut vous aider. Par exemple :

    import os

    SENDMAIL = "/usr/sbin/sendmail"  # sendmail location
    p = os.popen("%s -t -i" % SENDMAIL, "w")
    p.write("To: receiver@example.com\n")
    p.write("Subject: test\n")
    p.write("\n") # blank line separating headers from body
    p.write("Some text\n")
    p.write("some more text\n")
    sts = p.close()
    if sts != 0:
        print "Sendmail exit status", sts

### Comment éviter de bloquer dans la méthode `connect()` d’un connecteur réseau ?

The select module is commonly used to help with asynchronous I/O on sockets.

Pour empêcher une connexion TCP de se bloquer, il est possible de mettre le connecteur en mode lecture seule. Avec cela, au moment du `connect()`, la connexion pourra être immédiate (peu probable) ou bien vous obtiendrez une exception qui contient le numéro d’erreur dans `.errno`. `errno.EINPROGRESS` indique que la connexion est en cours, mais qu’elle n’a pas encore aboutie. La valeur dépend du système d’exploitation, donc renseignez-vous sur la valeur utilisée par votre système.

You can use the `connect_ex()` method to avoid creating an exception. It will just return the errno value. To poll, you can call `connect_ex()` again later – 0 or `errno.EISCONN` indicate that you’re connected – or you can pass this socket to select to check if it’s writable.

## Bases de données

### Existe-t’il des modules Python pour s’interfacer avec des bases de données ?

Oui.

Python 2.3 includes the `bsddb` package which provides an interface to the BerkeleyDB library. Interfaces to disk-based hashes such as `DBM` and `GDBM` are also included with standard Python.

La gestion de la plupart des bases de données relationnelles est assurée. Voir la page wiki DatabaseProgramming pour plus de détails.

### Comment implémenter la persistance d’objets en Python ?

The `pickle` library module solves this in a very general way (though you still can’t store things like open files, sockets or windows), and the `shelve` library module uses pickle and (g)dbm to create persistent mappings containing arbitrary Python objects. For better performance, you can use the `cPickle` module.

A more awkward way of doing things is to use pickle’s little sister, marshal. The `marshal` module provides very fast ways to store noncircular basic Python types to files and strings, and back again. Although marshal does not do fancy things like store instances or handle shared references properly, it does run extremely fast. For example, loading a half megabyte of data may take less than a third of a second. This often beats doing something more complex and general such as using gdbm with pickle/shelve.

### Why is cPickle so slow?

By default `pickle` uses a relatively old and slow format for backward compatibility. You can however specify other protocol versions that are faster:

    largeString = 'z' * (100 * 1024)
    myPickle = cPickle.dumps(largeString, protocol=1)

### If my program crashes with a bsddb (or anydbm) database open, it gets corrupted. How come?

Databases opened for write access with the bsddb module (and often by the anydbm module, since it will preferentially use bsddb) must explicitly be closed using the `.close()` method of the database. The underlying library caches database contents which need to be converted to on-disk form and written.

If you have initialized a new bsddb database but not written anything to it before the program crashes, you will often wind up with a zero-length file and encounter an exception the next time the file is opened.

### I tried to open Berkeley DB file, but bsddb produces bsddb.error: (22, “Invalid argument”). Help! How can I restore my data?

Don’t panic! Your data is probably intact. The most frequent cause for the error is that you tried to open an earlier Berkeley DB file with a later version of the Berkeley DB library.

Many Linux systems now have all three versions of Berkeley DB available. If you are migrating from version 1 to a newer version use db_dump185 to dump a plain text version of the database. If you are migrating from version 2 to version 3 use db2_dump to create a plain text version of the database. In either case, use db_load to create a new native database for the latest version installed on your computer. If you have version 3 of Berkeley DB installed, you should be able to use db2_load to create a native version 2 database.

You should move away from Berkeley DB version 1 files because the hash file code contains known bugs that can corrupt your data.

## Mathématiques et calcul numérique

### Comment générer des nombres aléatoires en Python ?

Le module `random` de la bibliothèque standard comprend un générateur de nombres aléatoires. Son utilisation est simple :

    import random
    random.random()

Le code précédent renvoie un nombre à virgule flottante aléatoire dans l’intervalle [0, 1[.

Ce module fournit beaucoup d’autres générateurs spécialisés comme :

- `randrange(a, b)` génère un entier dans l’intervalle [a, b[.

- `uniform(a, b)` génère un nombre à virgule flottante aléatoire dans l’intervalle [a, b[.

- `normalvariate(mean, sdev)` simule la loi normale (Gaussienne).

Des fonctions de haut niveau opèrent directement sur des séquences comme :

- `choice(S)` sélectionne au hasard un élément d’une séquence donnée

- `shuffle(L)` mélange une liste en-place, c-à-d lui applique une permutation aléatoire

Il existe aussi une classe `Random` qu’il est possible d’instancier pour créer des générateurs aléatoires indépendants.