Python arrive en version 3.1

Posté par (page perso) . Modéré par tuiu pol.
Tags :
36
2
juil.
2009
Python
Le langage de programmation Python arrive dans une version 3.1 qui marque la maturation de la branche 3.x. Le passage à Unicode par défaut pour les chaînes de caractères dans Python 3.0 était source de nombreuses régressions au niveaux des performances. Celles-ci ont été gommées par la réécriture en C de la bibliothèques d'entrées/sorties (io) et l'optimisation des décodeurs des principaux jeux de caractères (ISO-8859-1, UTF-8 et UTF-16).

Les nouvelles fonctionnalités ne sont pas en reste. Le type « dictionnaire ordonné », qui conserve l'ordre d'insertion des éléments, souvent demandé par les utilisateurs, fait enfin son entrée dans le langage sous le nom « odict » (PEP 372: Adding an ordered dictionary to collections). L'instruction « with » accepte désormais d'écrire plusieurs contextes sur la même ligne, rendant contextlib.nested() désuet.

La seconde partie de la dépêche détaille les nouveautés de la version 3.1. Nouveautés de Python 3.1

Formatage des nombres flottants

Le type float de Python utilise le format IEEE 754 qui stocke les nombres en base 2. La conversion en une chaîne de caractères (base 10, décimal) surprend bon nombre de débutants à cause d'erreurs d'arrondis provenant du changement de base et de la précision limitée du format IEEE 754 (généralement 64 bits dont 52 pour la mantisse). Exemple : 0.1 * 2 (ou simplement « print repr(0.2) ») donne 0.20000000000000001 plutôt que 0.2 dans l'interprète interactif. Les raisons de ce problème, qui n'est pas spécifique à Python, sont détaillées dans la FAQ (Why are floating point calculations so inaccurate?).

Python 3.1 utilise désormais l'algorithme de David Gay pour utiliser une représentation (décimale) plus concise des nombres flottants. repr(1.1) renvoie simplement « 1.1 » au lieu de « 1.1000000000000001 ». Relire le ticket Use shorter float repr when possible pour voir le chemin parcouru pour obtenir ce résultat. Les développeurs se sont également inspirés du code source Tcl, en particulier de la fonction Tcl_PrintDouble.

Ce problème ne concernait pas str(nombre) qui utilise un algorithme différent.

Pour éviter les problèmes de conversion entre les bases 2 et 10, vous pouvez également utiliser le type Decimal qui travaille en base 10.

Séparateur des milliers et méthode bit_length

Au passage, le formatage des nombres entiers et flottants supporte désormais le séparateur des milliers (PEP 378: Format Specifier for Thousands Separator).

Le type int gagne la méthode bit_length() qui calcule le nombre de bits nécessaires pour représenter le nombre en binaire.

Format {}

Il n'est plus obligatoire de numéroter les arguments en utilisant la méthode format(). "{0} {1}!".format("Hello", "World") peut maintenant s'écrire simplement "{} {}!".format("Hello", "World")
importlib

Le nouveau module importlib offre une implémentation complète, portable, et écrite entièrement en Python de l'instruction import et de la fonction __import__. C'est une étape importante de la documentation des actions réalisées durant les imports, et va permettre de tester facilement de nouveaux comportements comme les imports paresseux ou des bacs à sable (pour la sécurité).

Amélioration du module unittest

Il est désormais possible d'ignorer certains tests en utilisant le décorateur : @unittest.skipUnless(condition, raison) De nombreuses méthodes ont également été ajoutées : assertSetEqual(), assertDictContainsSubset(), assertListEqual(), assertTupleEqual(), assertRaisesRegexp(), assertIsNone(), etc.

Ce n'est pas tout !

La liste des nouveautés est trop longue pour être détaillée ici. Je vous invite donc à consulter What's new in 3.1? pour en obtenir la liste complète.

Rappels sur la branche 3.x

Pour rappel, Python 3.0 a volontairement brisé la rétro-compatibilité, après une petite dizaine d'années passées en compagnie de la branche 2.x, pour améliorer la conception du langage. En particulier, les chaînes de caractères sont maintenant en Unicode par défaut, et les chaînes d'octets sont clairement séparées (la concaténation octets + caractères est interdite). Cette version était aussi l'occasion d'un dépoussiérage du langage (réorganisation de la bibliothèque standard, simplification du langage, etc.). Relire la dépêche sortie de Python 3.0 version finale pour les détails.

Pendant ce temps, la branche 2.x continue d'évoluer. Bien que la date de sortie de la version 2.7 ne soit pas encore fixée, on peut déjà dire que cette version contiendra bon nombre des nouveautés de Python 3.1 (se référer au document de travail What's New in Python 2.7)

La migration de Python 2 vers Python 3 est facilitée par le script 2to3. Tant que les bibliothèques majeures ne seront pas disponibles pour Python3, la majorité des applications continueront à utiliser Python2. Quelques projets expérimentaux de portage existent : setuptools, Django ou zope.interface. Tandis que PyGTK ou PyQt ne sont pas encore disponibles pour Python3. Par contre, le compilateur d'interface XML vers Python PyQt est capable de générer du code Python3.

Installer et tester Python 3.1

Python 3.1 supporte l'ensemble des systèmes d'exploitations modernes. Des paquets binaires Windows et Mac OS X sont téléchargeables, et des paquets pour les distributions Linux/BSD devraient suivre rapidement. En attendant, vous pouvez déjà tester en compilant vous même le code source et en l'installant dans le dossier de votre choix. Exemple :./configure --prefix=/opt/python31 && make && make install La compilation prend cinq minutes. Le code source est distribué sous la Python Software Foundation License (de type BSD).

Python (2.4, 2.5, voire 2.6) est aujourd'hui préinstallé sur la plupart des distributions Linux, NetBSD, OpenBSD et Mac OS X.

Sources

Cette dépêche a été rédigée à partir de l'article Python 3.1, une nouvelle version dans la branche 3.x (site du zéro), du journal de Skorps, du journal de haypo, d'une dépêche refusée de Bruno Michel, ainsi que de la documentation Python 3.1.
  • # Beau boulot

    Posté par (page perso) . Évalué à 8.

    Dépêche très claire et bien détaillée, un beau boulot. Merci!
  • # Quand switcher ?

    Posté par . Évalué à 4.

    Je continue actuellement mes développements en 2.X. D'après vous, quels seront les éléments déclencheurs qui favoriseront le passage à la branche 3.x. La disponibilité de modules compatibles ? De gros projets qui franchiront le pas ? Quels sont, pour vous, les critères qui vont faire que vous allez switcher ? Votre avis m'intéresse.
    • [^] # Re: Quand switcher ?

      Posté par (page perso) . Évalué à 10.

      Je pense que tant que les librairies que tu utilise ne seront pas portées (comme numpy, scipy, matplotlib pour ma part), tu ne peux pas switcher sur python 3.x.

      Néanmoins, si tu as python >= 2.6, tu peux appeler ton script python avec l'option -3 et déjà corriger toutes les insultes qu'il te lancera. Si tu n'a rien d'écrit en C dans ton programme, une fois tous les "warning" résolut, tout devrait être bon pour le portage quand les librairies seront prêtes pour python 3.x.

      C'est en tout cas la stratégie que je vais utiliser pour mes projets.
    • [^] # Re: Quand switcher ?

      Posté par . Évalué à 5.

      Je crois que la sortie de cette version 3.1 est le signal pour montrer que la branche 3 est mure et que le portage des modules peut commencer sans crainte.

      Par contre, le fait que la branche 2 intègre la plupart des nouveautés de la 3 rend à la fois plus facile la migration à la fois moins nécessaire... Vu que des projets comme unladen-swallow visent à la fois la 2 et la 3, les deux ont encore de beaux jours devant eux.

      J'aimerai également bien avoir l'avis de ceux qui ont ou vont switcher, en particulier nous autres étrangers à la langue exotique. Pour ma part le boulot a été énorme lorsque j'ai migré mes projets en unicode. Je redoute de retomber sur des problèmes à ce niveau !
  • # PyQt4 et Python v3

    Posté par (page perso) . Évalué à 2.

    Je n'ai pas testé la chose, donc je m'exprime sans vraiment savoir, mais des indices concordants instillent le doute quand à l'égal dupport de Python v3 pat PyGtk et PyQT4.

    Comme par exemple http://www.riverbankcomputing.co.uk/software/pyqt/download qui permet de télécharger des binaires windows pour Python 3.

    L'annonce de support a été faite par Phil Thompson le 4 avril :
    http://www.mail-archive.com/pyqt%40riverbankcomputing.com/ms(...)
    (dans le même fil, un chemin de migration a été proposé par Giovanni Bajo : http://www.mail-archive.com/pyqt%40riverbankcomputing.com/ms(...) )

    Mes 2¢
  • # Simplification de format {}

    Posté par (page perso) . Évalué à 2.

    C'est un petit détail, mais qui simplifie tellement la vie :)
    • [^] # Re: Simplification de format {}

      Posté par (page perso) . Évalué à 3.

      Oui, mais on n'est pas encore au niveau de simplicité de l'ancien « "truc %s" % "pouet ».
    • [^] # Re: Simplification de format {}

      Posté par . Évalué à 4.

      Mouai, je trouve que cela reste quand même assez mauvais par rapport a ce qui pourrait être fait:
      "%{prenom} %{nom} a %03d{age}."
      cela serait quand même plus lisible que d'avoir d'un coté les "insert de formatage" de l'autre les variables référencées..

      Je crois que c'est possible en Ruby (mais sans la souplesse des convertisseur a la printf malheureusement).
      • [^] # Re: Simplification de format {}

        Posté par (page perso) . Évalué à 3.

        Je n'ai pas compris si tu demandais si c'était possible ou bien que tu préfères le formatage avec %. En Python3, ça donne : "{prénom} {nom} a {age:03}".format(prénom="victor", nom="stinner", age=26) ou bien
        "%(prénom)s %(nom)s a %(age)03d" % {'prénom': "victor", 'nom': "stinner", 'age': 26} Les deux donnent le résultat « victor stinner a 026 ». Perso je préfère largement format, car avec % on peut facilement oublier le suffixe "s" (en particulier pour les traducteurs), et la syntaxe des arguments est plus simple.

        Les arguments pour/contre format et % ont déjà été discuté dans le journal http://linuxfr.org//~cho7/27909.html

        PS : Python3 accepte les accents dans le nom des symboles ;-)
        • [^] # Re: Simplification de format {}

          Posté par . Évalué à 4.

          Une forme intéressante:
          >>> prenom='toto'
          >>> nom='tata'
          >>> print("prenom: %(prenom)s nom: %(nom)s" % locals())
          prenom: toto nom: tata
          • [^] # Re: Simplification de format {}

            Posté par . Évalué à 1.

            Interressant.

            Est-il possible de construire une 'macro' qui rajouterai le '% locals' de la fin?
            ie d'avoir au final 'putf("prenom: %(prenom)s nom: %(nom)s")' ?

            Sinon de toute façon je trouve cette forme interressante meme si c'est un peu curieux de devoir rajouter le 's' a la fin plutot qu'au debut (a la printf), encore mieux serait de ne pas avoir a mettre de specifieur format pour les affichages par defaut..
            Par exemple %20s(name) %03d(age) si tu veux preciser la taille
            mais %(name) et %(age) autrement..
            • [^] # Re: Simplification de format {}

              Posté par . Évalué à 7.

              Est-il possible de construire une 'macro' qui rajouterai le '% locals' de la fin?
              Oui:
              import sys
              def putf(string):
              ____print string % sys._getframe().f_back.f_locals

              foo = 'bar'
              putf("truc: %(foo)s")
  • # python2

    Posté par . Évalué à 3.

    python2 marche tres bien et continuera d'être utilisé pendant des dizaines d'années
    python3 est vraiment sympa quand tu traite des octects par contre. (en tout cas c'est mon utilisation principale)
    le seul truc chiant finalement, c'est de trjs taper "print blah" au lieu de "print (blah)" par habitude... ;)
    • [^] # Re: python2

      Posté par . Évalué à 5.

      Des dizaines d'années, faut pas exagérer mais Python ne va effectivement pas disparaitre tout de suite. :o)

      > le seul truc chiant finalement, c'est de trjs taper "print blah" au lieu de "print (blah)" par habitude... ;)

      Pour te débarrasser de cette habitude, rajoute la ligne suivante dans tes scripts et ton PYTHONSTARTUP pour l'interpréteur interactif.

      from __future__ import print_function


      Désormais l'interpréteur râlera quand tu n'utiliseras pas la notation fonctionnelle. C'est radical.
  • # Dictionnaire ordonne

    Posté par . Évalué à 3.

    Mis-a-part pour optimiser la recherche des tuples, a quoi sert un dictionnaire ordonne ?
    • [^] # Re: Dictionnaire ordonne

      Posté par (page perso) . Évalué à 5.

      odict permet de parcourir les clés et valeurs dont leur ordre d'insertion, ce que ne permet pas le type dict (qui n'est pas ordonnée : l'ordre dépend de l'algorithme de hachage). Tu trouveras plus d'explication sur odict dans la PEP (citée au début de la dépêche) :
      http://www.python.org/dev/peps/pep-0372/
      • [^] # Re: Dictionnaire ordonne

        Posté par (page perso) . Évalué à 2.

        En effet, c'est le truc qui m'aurais bien servi au taf au lieu d'associer mon dict à une liste pour l'ordonner... Oui je sais c'est crade, mais c'était du dev "à l'arache" et je découvrais python.
        Qu'on apprends assez vite d'ailleurs et qui laisse un bon goût dans la bouche en plus !

        En passant, y'avait-il une technique élégante pour faire ça ou fallait-il mieux penser son code pour éviter ce cas de figure ?
  • # Bit_length

    Posté par (page perso) . Évalué à 2.

    > Le type int gagne la méthode bit_length() qui calcule le nombre de bits nécessaires pour représenter le nombre en binaire.

    Ha. Y'avait pas la fonction log en base 2 ?
    Car s'il y a bien une fonction inutile (et que j'ai bien compris à quoi sert bit_length), c'est bien bit_lenght !
    • [^] # Re: Bit_length

      Posté par . Évalué à 7.

      M'est avis qu'un log base 2 avec jolie conversions int/float/int et le développement limité au milieu, c'est peut-etre un poil overkill pour faire ce que fait bit_length...
    • [^] # Re: Bit_length

      Posté par (page perso) . Évalué à 10.

      Y'avait pas la fonction log en base 2 ?

      Il est possible d'utiliser math.ceil(math.log(abs(x + 1)) / math.log(2)), mais tu vas rapidement perdre en précision car ça utilise des nombres flottants de taille fixe. Le type int de Python3 a une taille illimitée et peut faire plusieurs milliers/millions de bits.

      Exemple :x=2**100-1; math.ceil(math.log(abs(x+1)) / math.log(2)), x.bit_length()
      x=2**100; math.ceil(math.log(abs(x+1)) / math.log(2)), x.bit_length()
      donne (100, 100)
      (100, 101)

      À partir de 100 bits, la fonction utilisant math commence déjà à renvoyer des résultats faux.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.