<> = Introduction = Python est né il y a déjà quinze ans, cela peut paraître vieux pour un langage de programmation mais en vérité, cela signifie que le langage a atteint la pleine maturité attendue des sages à l'octobre de leurs vies. Contrairement aux vieux sages, Python s'enrichit tous les jours de nouvelles fonctionnalités extrêmement puissantes retrouvés dans les langages dis modernes. = Python 2.5 Quoi de Neuf? = La version 2.5 de Python a été publiée le 19/09/2006. Cette nouvelle version ne contient aucune fonctionnalité nécessitant la modification de votre code produite sous les versions 2.4.X. Parmi les nouvelles fonctionnalités on peut citer: == Fonctions partielles == Python 2.5 fournit une fonction partial() dans le module functools (surtout utilisé dans le cas de la programmation fonctionnelle). La fonction partial() vous permet de projeter une transformation d'un espace n dans un espace de dimension n-m (n>m>0). Ainsi une fonction addUser(login, passe, domaine) donnerait pour un domaine constant une fonction addLocalUser(login, passe). {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import functools >>> def adduser(login, passe, domaine): ... print login ... print passe ... print domaine ... >>> DKR_adduser = functools.partial(adduser, domaine='dakar.vacances') >>> dir(DKR_adduser) ['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'args', 'func', 'keywords'] >>> DKR_adduser('Toto', 'Nono') Toto Nono dakar.vacances >>> }}} == Enfin un Opérateur ternaire == L'opérateur dit ternaire fournit dans d'autres langages tels que C/C++, PHP produit le même effet que le code suivant: {{{ if a == 'abc': b = '2' else: b = 3 (Dans d'autres langages on écrirait if a == 'abc' ? '2' : 3 ) }}} La version 2.5 de Python permet à présent de condenser le bloc ci-dessus: {{{ b = '2' if a == 'abc' else 3 root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a=1 >>> b = '2' if a == 'abc' else 3 >>> b 3 >>> a='abc' >>> b = '2' if a == 'abc' else 3 >>> b '2' >>> }}} Notez que bien que même si le mélange de type ci-dessus ne produit pas d'erreur, ce n'est certainement pas la meilleure façon d'éviter des bogues difficilement détectables. == Fédération try/except/finally == Avant la version 2.5, il était possible d'utiliser ''finally ''pour s'assurer qu'une partie du code était exécutée quoi qu'il arrive ou définir des blocs ''except'' supplémentaires pour intercepter des exceptions particulières mais les deux mécanismes n'étaient pas combinables. A présent le code suivant est tout à fait valide: {{{ try: bloc-0 except Exception-0: gestionnaire-0 except Exception-1: gestionnaire-1 except Exception-2: gestionnaire-2 else: gestionnaire-autre finally: code-à-exécuter-quoi-quil-arrive }}} Le bloc-0 est exécuté et si si une exception est levée, les différents blocs d'exceptions sont testés, si l'exception levée est de type Exception-0, le gestionnaire d'exception gestionnaire-0 est exécuté, sinon, si l'exception levée est de type Exception-1, le gestionnaire d'exception gestionnaire-1 est exécuté, etc. Si aucune exception n'a été levée, le bloc gestionnaire-autre est évaluée. Quoi qu'il arrive (même si une exception a été levée et que le gestionnaire de l'exception a générer une erreur), le bloc code-à-exécuter-quoi-quil-arrive sera exécuté == Générateurs modifiable == Les générateurs ([[http://www.python.org/dev/peps/pep-0255/|http://www.python.org/dev/peps/pep-0255/]]) sont des fonctions qui ont une mémoire dans le sens des exécutions successives conservent le contexte du générateur. Les générateurs sont activés avec le mot clé yield, ils servent principalement à produire des itérateurs: {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> class UneClasse: def __init__(self): self.MaVariable = [1,2,3,4] def itere(self): i = 0 while i < len(self.MaVariable): yield self.MaVariable[i] i += 1 ... ... ... ... ... ... ... ... >>> >>> UnObjet = UneClasse() iterateur = UnObjet.itere()>>> >>> iterateur >>> dir(iterateur) ['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'close', 'gi_frame', 'gi_running', 'next', 'send', 'throw'] >>> print iterateur.next() 1 >>> print iterateur.next() 2 >>> print iterateur.next() 3 >>> print iterateur.next() 4 >>> print iterateur.next() Traceback (most recent call last): File "", line 1, in StopIteration >>> }}} On notera que contrairement au C++ avec lequel il est possible de déférencer un itérateur pour en obtenir la valeure, il est nécessaire avec Python d'invoquer la méthode next() pour obtenir la valeur de l'itérateur. Notez que l'exception StopIteration est levée à la fin de la liste. Avec la version 2.5, Python fournit la méthode close() qui permet de libérer les ressources associées au générateur. Un générateur permet d'invoquer une fonction contenant le mot clé yield qui va suspendre l'exécution en permettant de revenir là où l'exécution était suspendue. Notons aussi que l'assignation iterateur = UnObjet.itere() ne provoque pas l'exécution de la fonction, Python détecte la présence de yield et crée un objet de type générateur: {{{ >>> iterateur }}} Tous les langages fournissant un générateur permettent généralement d'envoyer une valeur au générateur, ceci sert principalement à supporter la fonctionnalité de coroutine permettant de fournir des listes infinies, des tâches coopératives, tubes, etc ([[http://en.wikipedia.org/wiki/Coroutine#Implementations_for_Python|http://en.wikipedia.org/wiki/Coroutine#Implementations_for_Python]]). Cette fonctionnalité a maintenant été introduite avec la version 2.5: {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> class UneClasse: def __init__(self): self.MaVariable = [1,2,3,4] def itere(self): i = 0 while i < len(self.MaVariable): val = yield self.MaVariable[i] if val == None: i += 1 else: i = val = 0 ... ... ... ... ... ... ... ... ... ... ... >>> >>> MonObjet=UneClasse() >>> dir(MonObjet) ['MaVariable', '__doc__', '__init__', '__module__', 'itere'] >>> MonIterateur=MonObjet.itere() >>> dir(MonIterateur) ['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'close', 'gi_frame', 'gi_running', 'next', 'send', 'throw'] >>> MonIterateur.next() 1 >>> MonIterateur.next() 2 >>> MonIterateur.next() 3 >>> MonIterateur.send(6) 1 >>> MonIterateur.next() 2 >>> MonIterateur.next() 3 >>> MonIterateur.send(-12) 1 >>> MonIterateur.next() 2 >>> }}} En de la méthode send(), les générateurs disposent à présent de deux autre méthodes comme vous pouvez le voir dans le listing ci-dessus: throw(type, value=None, traceback=None) et close(). Elles servent respectivement à envoyer une exception à l'intérieur du générateur et à déclencher une exception `GeneratorExit` pour terminer l'itération. == Gestion des contextes (with) == La plupart des langages de programmation fournissent le mot clé ''with'', par contre l'utilisation de ce mot-clé est différent sous Python. Le mot-clé ''with'' sous Python vous permet de définir un bloc de code sous un certain contexte à la sortie duquel, un ensemble de routines de nettoiement sont exécutés. Un contexte est un groupement homogène caractéristique d'une série opérations indissociables. Un exemple typique de contexte est constitué de la transaction sur une base de données relationnelles. Le contextes effectue certaines opérations au début de la transaction (création de la transaction, allocation des ressources nécessaires, etc) et à la fin de la transactions, d'autres opérations sont effectuées (sauvegarde - commit - ou annulation - rollback --). Pour créer un contexte, il suffit d'ajouter à votre classe les méthodes {{{__enter__()}}} et {{{__exit__()}}} qui contiennent respectivement le code d'initialisation du contexte et le code de sortie (gestion des exceptions, fermetures des fichiers et connexions aux bases de données ouverts, etc). Si vous voulez définir vos propres contextes référez-vous à la documentation de référence PEP-343 ([[http://docs.python.org/whatsnew/pep-343.html|http://docs.python.org/whatsnew/pep-343.html]]). Certains modules et classes Python disposent d'une gestion intégrée des contextes utilisable en invoquant le mot-clé ''with''. {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from __future__ import with_statement >>> with open('/tmp/fichier.txt', 'r') as f: ... for line in f: ... print line ... with Mon truc >>> dir(f) ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'close', 'closed', 'encoding', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines'] >>> f.readlines() Traceback (most recent call last): File "", line 1, in ValueError: I/O operation on closed file }}} On notera que la fin du contexte a déclenché la fermeture du fichier de sorte que l'appel à f.readlines() a généré une exception d'entrée sortie. Notez également que le contexte est exposé dans {{{__future__}}} et sera activé à partir de la version 2.6. Un autre exemple: {{{ connexion = ConnexionDB() with connexion as cursor: cursor.execute('insert into ...') cursor.execute('delete from ...') # ... class ConnexionDB: def cursor (self): "Renvoie un objet curseur et ouvre une nouvelle transaction" def commit (self): "Commit la transaction" def rollback (self): "Annule la transaction" def __enter__ (self): # Code pour commençer une nouvelle transaction cursor = self.cursor() return cursor }}} == Méthode __missing__ de la classe dict == La classe dictionnaire dispose à présent d'une méthode {{{__missing__()}}} dont la surcharge vous permet de gérer les clés inexistant. {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> Dict0={0:0,1:1,2:2} >>> class MonDict(dict): ... def __missing__(self, key): ... self[key] = None ... return None ... >>> dir(MonDict) ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__missing__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', '__weakref__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] >>> Dict1=MonDict(Dict0) >>> dir(Dict1) ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__missing__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__str__', '__weakref__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] >>> Dict1 {0: 0, 1: 1, 2: 2} >>> Dict1[3] >>> Dict1 {0: 0, 1: 1, 2: 2, 3: None} >>> }}} == Méthodes partition et rpartition de la classe string == Ces méthodes permettent le partitionnement des chaînes de caractère et renvoie des tuples contenant la partie droite de la chaîne partitionnée, le séparateur et la partie droite. {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a="Python 2.5 déchires sa race" >>> dir(a) ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__str__', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] >>> a.partition('sa') ('Python 2.5 d\xc3\xa9chires ', 'sa', ' race') >>> }}} == Méthodes startswith et endwith == Les méthodes de chaîne startswith et endswith acceptent les tuples comme arguments: {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a=['image1.jpg', 'image2.png', 'doc.odt', 'image3.gif', 'image4.xpm'] >>> for i in a: ... if i.endswith(('.jpg','.png','.gif','.xpm')): ... print i, "est peut etre une image" ... image1.jpg est peut etre une image image2.png est peut etre une image image3.gif est peut etre une image image4.xpm est peut etre une image >>> }}} == Fonctions min et max acceptent des fonctions == Les fonctions min et max acceptent une fonction comme argument: {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def monordre(s): ... try: ... nombre = int(s) ... return nombre ... except: ... return len(s) ... >>> print max(['gfter', '150', 1, 'abd'], key=monordre) 150 >>> }}} == Les fonctons any() et all() == Les deux nouvelles fonctions d'expressions binaires permettent d'exprimer plus clairement les opérations binaires classiques ''and'' et ''or'': {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a=1 >>> b=11 >>> all([a>2, b<2]) False >>> any([a>2,b>12]) False >>> any([a>2,b<12]) True >>> }}} ''any()'' renvoie True si et si seulement si l'une des expression est vraie alors que ''all()'' renvoie vrai si et seulement si toutes les expressions sont vraies == Intégration de SQLite3 == Le module pysqlite est intégrée à la bibliothèque standard de Python sous le nom de sqlite3. {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import sqlite3 >>> dir(sqlite3) ['Binary', 'Cache', 'Connection', 'Cursor', 'DataError', 'DatabaseError', 'Date', 'DateFromTicks', 'Error', 'IntegrityError', 'InterfaceError', 'InternalError', 'NotSupportedError', 'OperationalError', 'OptimizedUnicode', 'PARSE_COLNAMES', 'PARSE_DECLTYPES', 'PrepareProtocol', 'ProgrammingError', 'Row', 'SQLITE_ATTACH', 'SQLITE_CREATE_INDEX', 'SQLITE_CREATE_TABLE', 'SQLITE_CREATE_TEMP_INDEX', 'SQLITE_CREATE_TEMP_TABLE', 'SQLITE_CREATE_TEMP_TRIGGER', 'SQLITE_CREATE_TEMP_VIEW', 'SQLITE_CREATE_TRIGGER', 'SQLITE_CREATE_VIEW', 'SQLITE_DELETE', 'SQLITE_DENY', 'SQLITE_DETACH', 'SQLITE_DROP_INDEX', 'SQLITE_DROP_TABLE', 'SQLITE_DROP_TEMP_INDEX', 'SQLITE_DROP_TEMP_TABLE', 'SQLITE_DROP_TEMP_TRIGGER', 'SQLITE_DROP_TEMP_VIEW', 'SQLITE_DROP_TRIGGER', 'SQLITE_DROP_VIEW', 'SQLITE_IGNORE', 'SQLITE_INSERT', 'SQLITE_OK', 'SQLITE_PRAGMA', 'SQLITE_READ', 'SQLITE_SELECT', 'SQLITE_TRANSACTION', 'SQLITE_UPDATE', 'Statement', 'Time', 'TimeFromTicks', 'Timestamp', 'TimestampFromTicks', 'Warning', '__builtins__', '__doc__', '__file__', '__name__', '__path__', 'adapt', 'adapters', 'apilevel', 'complete_statement', 'connect', 'converters', 'datetime', 'dbapi2', 'enable_callback_tracebacks', 'paramstyle', 'register_adapter', 'register_converter', 'sqlite_version', 'sqlite_version_info', 'threadsafety', 'time', 'version', 'version_info', 'x'] >>> }}} Notez que si vous compilez le code de Python vous-même, il ne contient pas le code de la bibliothèque SQLite, mais seulement un wrapper, vous devrez donc installer la bibliothèque SQLite ainsi que les fichiers en-tes avant de lancer la compilation de Python. {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import sqlite3 >>> connexion = sqlite3.connect('/tmp/mabase.db') >>> curseur = connexion.cursor() >>> curseur.execute('CREATE TABLE utilisateur(id int, nom varchar(15), prenoms varchar(35))') >>> curseur.execute("""INSERT INTO utilisateur VALUES(0, 'Toto', 'NoNo')""") >>> enreg = (1, 'NoNo', 'Toto') >>> curseur.execute('INSERT INTO utilisateur VALUES(?,?,?)', enreg) >>> curseur.execute('SELECT * FROM utilisateur') >>> dir(curseur) ['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'arraysize', 'close', 'connection', 'description', 'execute', 'executemany', 'executescript', 'fetchall', 'fetchmany', 'fetchone', 'lastrowid', 'next', 'row_factory', 'rowcount', 'setinputsizes', 'setoutputsize'] >>> for ligne in curseur: ... print ligne ... (0, u'Toto', u'NoNo') (1, u'NoNo', u'Toto') }}} Notez dans l'exemple ci-dessus qu'après une opération de type SELECT, nous avons utilisé le curseur comme un itérateur, on aurait pu invoquer la famille des méthodes fetch(). == Importation absolues et relatives == Jusqu'à la version 2.4 les importations de modules étaient relatives au module qui effectuait l'importation de sorte qu'il arrivait souvent qu'un module utilisateur soit importé alors qu'un module standard était recherché. Exemple: {{{ paquet/ paquet/main.py paquet/functools.py }}} Si le code de main importe le module functools, le module functools contenu dans le repèrtoire paquet sera importé, ce qui ne pose aucun problème s'il s'agit du module désiré. Par contre si le module standard functools est désiré, on sera bien embêté. Avec la version 2.6 vous pouvez changer le comportement d'importation relatif par défaut: {{{ from __future__ import absolute_import }}} Il sera toujours possible d'ordonner l'importation relative en utilisant la notation à point: {{{ from . import functools }}} == Le module ctypes == Le paquet ctypes permet d'invoquer des fonctions contenues dans des bibliothèques partagées ou des DLL. {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import ctypes >>> crypto = ctypes.CDLL('libcrypt.so.1') >>> crypto.crypt('TotoNono', '$$') 1076454720 >>> }}} == Le module ElementTree (http://effbot.org/zone/element-index.htm) == ElemTree represente un document XML comme une arborescence de noeuds. Avec ElementTree, l'analyse des fichiers XML est devenu extrêmement simple: {{{ root@xen198:~# python Python 2.5 (r25:51908, Sep 20 2006, 11:34:22) [GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import urllib >>> from xml.etree import ElementTree as ET >>> flux=urllib.urlopen('http://www.linux.com/index.rss') >>> arbre=ET.parse(flux) >>> racine=arbre.getroot() >>> def traverse(noeud, indent=0): for c in noeud.getchildren(): print ' '*indent, c.tag, ':', c.text traverse(c, indent+1) ... ... ... ... >>> traverse(racine) {http://purl.org/rss/1.0/}channel : {http://purl.org/rss/1.0/}title : Linux.com {http://purl.org/rss/1.0/}link : http://www.linux.com/ {http://purl.org/rss/1.0/}description : The Enterprise Linux Resource {http://purl.org/dc/elements/1.1/}language : en-us {http://purl.org/dc/elements/1.1/}rights : Copyright 2004, OSTG - Open Source Technology Group, Inc. All Rights Reserved. {http://purl.org/dc/elements/1.1/}date : 2006-11-13T12:10:14+00:00 {http://purl.org/dc/elements/1.1/}publisher : LiNUX.COM {http://purl.org/dc/elements/1.1/}creator : info@linux.com {http://purl.org/dc/elements/1.1/}subject : Linux {http://purl.org/rss/1.0/modules/syndication/}updatePeriod : hourly {http://purl.org/rss/1.0/modules/syndication/}updateFrequency : 1 {http://purl.org/rss/1.0/modules/syndication/}updateBase : 1970-01-01T00:00+00:00 {http://purl.org/rss/1.0/}items : {http://www.w3.org/1999/02/22-rdf-syntax-ns#}Seq : ............................ }}} == Le module hashlib == Un module hashlib a été ajouté dans le but de remplacer à terme les modules md5 et sha. En plus de ces modules, hashlib fournit les hashages tels que SHA-224, SHA-256, SHA-384, SHA-512, etc. haslib utilise OpenSSL lorsque celui-ci est disponible profitant ainsi des implémentations optimisées des algorithmes sur l'architecture hôte. == == == Le module wsgiref == WSGI (Web Server Gateway Interface) est un standard définissant les interactions entre les applications Python et les serveurs web de façon générale. Le module wsgiref est une implémentation de référence de la spécification WSGI 1.0. Le module contint un serveur web pour exécuter un application WSGI. Il est utilisé pour des tests et non en production. == Références == * [[http://docs.python.org/whatsnew/|http://docs.python.org/whatsnew/]] * [[http://www.onlamp.com/lpt/a/6764|http://www.onlamp.com/lpt/a/6764]] * [[http://en.wikipedia.org/wiki/Coroutine|http://en.wikipedia.org/wiki/Coroutine]] * [[http://docs.python.org/whatsnew/pep-343.html|http://docs.python.org/whatsnew/pep-343.html]] * [[http://www.sqlite.org/|http://www.sqlite.org/]] * [[http://www.python.org/peps/pep-0333.html|http://www.python.org/peps/pep-0333.html]] * [[http://www.python.org/peps/pep-0249.html|http://www.python.org/peps/pep-0249.html]] * [[http://www.python.org/dev/peps/pep-0255/|http://www.python.org/dev/peps/pep-0255]]