Python 3.3 est sorti

61
2
oct.
2012
Python

La version 3.3 de Python est sortie ce 29 septembre. Pour rappel, Python « est un langage de programmation multi‐paradigme. Il favorise la programmation impérative structurée et orientée objet. Il est doté d’un typage dynamique fort, d’une gestion automatique de la mémoire par ramasse‐miettes et d’un système de gestion d’exceptions ; il est ainsi similaire à Perl, Ruby, Scheme, Smalltalk et Tcl ». Merci Wikipédia.

Cette version 3.3 est donc la nouvelle version de production de la branche 3. Elle cohabite avec la version 2.7.3 de la branche 2.7. Cette nouvelle version apporte, entre autres, les fonctionnalités suivantes :

  • amélioration de la syntaxe des générateurs ;
  • un module venv capable de créer des environnement Python virtuels, tout comme VirtualEnv ;
  • revue du stockage interne des caractères, ce qui permet d’économiser de la mémoire ;
  • nouvelle façon de définir et placer les paquets d’un projet Python ;
  • des améliorations concernant l’API du module os, ainsi qu’une remise à plat des Exceptions concernant les entrées‐sorties ;
  • amélioration de l’intégration Windows ;
  • fonction de hachage aléatoire activée par défaut (permettant de se prémunir contre l’attaque des dictionnaires et des tables de hachage) ;
  • et bien d’autres…

Retrouvez en seconde partie de dépêche une liste plus complète des nouveautés.

NdA : Merci à FlashCode, Antoine, Victor Stinner, Laurent Pointal, Emmanuel C, jcr83, Amine « nh2 » Brikci‐Nigassa, GeneralZod, crep4ever, Nÿco et Le Cancre Las pour leur participation active à cette rédaction en collaboration.

Sommaire

Nouveautés de Python 3.3

PEP 380 — Générateurs

La nouvelle syntaxe yield from <expr> permet à un générateur de renvoyer directement les valeurs d’un autre générateur. Cette nouvelle construction autorise le chaînage de générateurs (et plus généralement d’itérateurs), simplement. Cela permettra d’écrire des générateurs, dont le code se trouve découpé dans plusieurs fonctions, elles‐mêmes génératrices (et évitera d’avoir de trop grosses fonctions monolithiques dédiées à cette tâche).

PEP 405 — VirtualEnv

Le nouveau module venv permet la création d’environnements virtuels Python à la manière du célèbre virtualenv de Ian Bicking. Un environnement virtuel est une installation isolée de Python dans un répertoire spécifique du système de fichiers, comprenant son propre interpréteur, ses propres paquets et scripts, avec un éventuel lien vers l’installation du système. Du fait de la prise en compte par les développeurs de cet usage, il sera maintenant plus simple de manipuler ces environnements, avec de futurs outils sans doute mieux intégrés. À cet effet, une nouvelle commande a été introduite : pyvenv.

PEP 3155

Les fonctions et les classes ont un nouvel attribut __qualname__ représentant le chemin depuis le module de plus haut niveau jusqu’à leur définition.

Compression

  • lzma : le nouveau module lzma fournit la compression et la décompression utilisant l’algorithme LZMA (algorithme de 7-zip), incluant la prise en charge des formats de fichier .xz et .lzma ;
  • bz2  : le module bz2 a été complètement réécrit, et gère désormais tout objet offrant une interface de type fichier. Il gère également la compression et la décompression en parallèle des flux.

PEP 417 Tests unitaires

Le framework de tests unitaires unittest, inclus dans la bibliothèque standard, a été enrichi d’un module de mock : unittest.mock.
Les objets factices (Mock Objects) permettent de simuler le comportement des objets dans certaines conditions. Cette technique facilite l’écriture des tests unitaires et peut également accélérer leur exécution dans certains cas.

Fonction sendfile

Le module os dispose d’une nouvelle fonction sendfile() qui fournit une manière efficace zero‐copy, permettant de copier les données d’un descripteur de fichier (ou socket) à un autre. L’expression « zero‐copy » fait référence au fait que toute la copie entre les deux descripteurs est entièrement effectuée par le noyau, sans passage par l’espace utilisateur. sendfile() est utile pour copier efficacement le contenu d’un fichier du disque vers une socket réseau, par exemple pour envoyer un fichier à un pair. À noter que l’appel système sendfile() n’étant pas normalisé, l’utilisation de cette nouvelle fonction sera dépendante des contraintes de la plate‐forme (tous les types de descripteurs de fichiers ne sont pas admis en entrée comme en sortie, par exemple). Voir la page man de l’appel système sous‐jacent pour plus de détails.

PEP 393 — Stockage des chaînes de caractères

Le stockage des chaînes de caractères a été optimisé. Pour toute chaîne, une taille fixe de 1, 2 ou 4 octets par caractère est dorénavant utilisée, selon le plus haut codepoint stocké dans celle‐ci. Par exemple, les chaînes ne contenant que de l’ASCII (codes 0 à 127) n’utilisent ainsi qu’un octet par caractère, les chaînes en latin1 et latin9, deux octets.
L’utilisation mémoire est deux à trois fois meilleure par rapport à Python 3.2 et se rapproche des performances de Python 2.7.

PEP 414 — Transition Unicode Py2 vers Py3

La notation u"texte", qui est utilisée dans Python 2.x, pour dénoter des littéraux chaînes Unicode, est de retour dans Python 3.3 afin de faciliter l’écriture de code fonctionnant sur des versions 2 et 3 de Python. Cette PEP a été proposée par Armin Ronacher, et acceptée en moins de 15 jours.

Standardisation de la procédure d’importation

import est implémenté à l’aide du module importlib, ce qui, à terme, devrait éliminer les différences de comportement entre les diverses implémentations. De même, l’importation des modules utilise maintenant un verrou par module et n’est plus global pour l’importation de tous les modules.

PEP 3144 — Gestion des adresses IP

Le nouveau module ipaddress permet de manipuler des adresses IPv4 et IPv6. Il est basé sur le module ipaddr-py de Google.

PEP 3151 — Exceptions entrées‐sorties

La hiérarchie des exceptions liées à l’OS et aux entrées‐sorties a été simplifiée. Désormais, elles dérivent toutes de OSError (IOError, EnvironmentError, etc., restent pour la compatibilité et sont des alias d’OSError) et sont typées plus finement pour connaître le type exact de l’erreur. Par exemple, ouvrir un fichier inexistant lève l’exception FileNotFoundError.

PEP 397 — Lanceur Python pour Windows

Un lanceur Python pour Windows fait son arrivée, se basant sur le shebang placé en tête des modules Python pour identifier la version de l’interpréteur à utiliser (comme sous les Unix), avec deux lanceurs (comme il y avait un python.exe et un pythonw.exe) permettant de démarrer Python avec ou sans la console (scripts en .py ou .pyw). Le lanceur est installé dans le répertoire de Windows (et est donc automatiquement dans le PATH qui liste les exécutables – mais nécessite des droits d’administration pour être installé).

PEP 418 — Fonctions de gestion du temps

Nouvelles fonctions de mesure du temps apparaissent dans le module time : monotonic() (non touchée par des ajustements de l’horloge, par exemple par NTP), perf_counter() (temps précis), process_time() (consommation de temps processeur utilisateur et système pour le processus).

PEP 420 — Empaquetage

Un module Python, sous forme de répertoire, n’a plus besoin de la présence d’un fichier __init__.py en son sein pour obtenir le statut de module. De plus, il peut être réparti sur plusieurs dossiers.

PEP 362 — inspect.getsignature()

inspect.getsignature() offre un format simple et standard pour lire la signature d’une fonction (notamment ses arguments).

Module décimal

Le module decimal a été réécrit en C et est maintenant jusqu’à 120 fois plus rapide pour les applications qui utilisent intensément les décimales.

Module os

La plupart des fonctions du module os prenant un nom de fichier en paramètre acceptent maintenant un descripteur de fichier, quand le système de fichiers le supporte. Ceci permet de se prémunir des attaques de type symlink attack, la fonction shutil.rmtree() est maintenant sûre.

Fonctions de hachage

Le hash randomization est activé par défaut. Il limite les exploits liés aux collisions dans les fonctions de hachage. Voir le courriel http://mail.python.org/pipermail/python-dev/2011-December/115116.html pour plus de détails.

Gestionnaire d’erreur faulthandler

Un nouveau module faulthandler permet d’afficher le traceback Python (pile d’appels) lors d’un crash.

Divers

  • ajout du mode x à la fonction open(). open("fichier.txt", "x") crée le fichier ou échoue s’il existe déjà (création atomique du fichier) ;
  • print("Affiche moi ça immédiatement !", flush=True, end="") écrit directement la chaîne dans la console (en vidant le cache) ;
  • les méthodes subprocess.Popen.communicate() et threading.Lock.acquire() acceptent désormais un argument optionnel timeout, facilitant la programmation concurrentielle ;
  • nouvelle méthode datetime.datetime.timestamp() qui convertit un timestamp au format Epoch, l’inverse de datetime.datetime.fromtimestamp(epoch).

On constate avec cette nouvelle version de Python 3 un allègement de la consommation mémoire, grâce au nouveau stockage des chaînes Unicode et grâce aux dictionnaires d’attributs — PEP 393 et 412 respectivement.
Note : les PEP, ou Python Enhancement Proposals sont les documents proposés à la communauté pour les changements / améliorations dans le langage et les bibliothèques, un peu comme les RFC pour les protocoles de l’Internet. Le PEP 001 décrit cette organisation.

Enfin, à l’occasion de cette nouvelle sortie, le thème de la documentation a été entièrement revu, avec des couleurs plus neutres : comparez le thème pour la branche 3.x à celui de la branche 2.x.

Aller plus loin

  • # Module 'venv'

    Posté par  . Évalué à 6.

    Cela me semble une bonne nouvelle de voir le Python "officiel" entériner une pratique déjà bien implantée sur le terrain. Mais qu'apporte (ou enlève?) le nouveau module 'venv' par rapport à l'actuel 'virtualenv'? Mis à part le fait de ne pas avoir besoin d'être installé, évidemment…

    • [^] # Re: Module 'venv'

      Posté par  . Évalué à 3.

      L'intérêt c'est de fournir également les fondations pour construire des outils de plus haut-niveau par dessus comme virtualenvwrapper & cie …

    • [^] # Re: Module 'venv'

      Posté par  . Évalué à 5.

      L'intérêt est aussi de ne pas être basé sur des hacks, puisque la mécanique nécessaire à la reconnaissance des environnements virtuels est intégrée à l'interpréteur : là où virtualenv recopie des tas de fichiers de la bibliothèque standard (et en patche au moins un), pyvenv se contente de créer quelques liens symboliques et un fichier de config léger.

    • [^] # Re: Module 'venv'

      Posté par  (site web personnel) . Évalué à 1.

      Moins de bricolage pour les administrateurs système. On peut l'utiliser direct sans avoir besoin de changer des variables d'environnements.

  • # Enfin !

    Posté par  . Évalué à 2.

    Excellente nouvelle que cette sortie pour tous les utilisateurs Python, en espérant que les nouveautés tel que le support de la notation u"mon texte" permettent de convaincre les derniers projets à passer à p3k (à suivre sur Hall of Shame).

    • [^] # Re: Enfin !

      Posté par  . Évalué à 4.

      Sait-on pourquoi ça avait été retiré ?

      « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

      • [^] # Re: Enfin !

        Posté par  . Évalué à 7.

        Parce que les chaînes étant unicode par défaut dans Python 3, l'ancienne notation était sémantiquement superflue (u"foo" désigne exactement la même chose que "foo").

        • [^] # Re: Enfin !

          Posté par  . Évalué à 3.

          Merci.

          « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

  • # speed

    Posté par  (site web personnel) . Évalué à 1.

    le module decimal a été réécrit en C et est désormais bien plus rapide.

    La place mémoire réduite pour les chaînes de caractères se traduit aussi par de meilleures performances en terme de vitesse.


    Francky, fan de speed sur SPOJ

  • # Pour tester Python (et apprendre)

    Posté par  (site web personnel) . Évalué à 8.

    Le site Python Tutor permet de tester et tracer des scripts Python2 et Python3 (2.7 et 3.2 pour le moment). L'interface d'exécution pas à pas est très sympa.

    info via B.Cordeau

    Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

    • [^] # Re: Pour tester Python (et apprendre)

      Posté par  . Évalué à 2.

      Génial, je ne connaissais pas!
      Pour les élèves de la spécialité informatique ISN, ce sera plus simple que le debugger d'Eclipse.

      Un grand merci pour eux.

  • # Journal

    Posté par  (site web personnel) . Évalué à 5.

    Voir aussi le journal d'Antoine annonçant la release candidate 2 :
    https://linuxfr.org/users/pitrou/journaux/python-3-3-0-release-candidate-2
    (notamment pour voir les commentaires)

  • # Python 2, c'est fini

    Posté par  (site web personnel) . Évalué à 7.

    Au passage, il n'y aura pas de Python 2.8, et il n'y aura plus de nouvelles fonctionnalités sur la branche 2.7.

    Il n'y a plus qu'à attendre que les grandes bibliothèques passent toutes à Python 3 pour vraiment lancer le mouvement (PyQt est déjà compatible, Django 1.5 le sera, SQLAlchemy fonctionne, Matplotlib est bien avancé, il semble rester encore du boulot pour Twisted, PiL n'est pas être prête).

  • # Made in France

    Posté par  (site web personnel) . Évalué à 3.

    Python est un projet collaboratif international, mais je salue quand même le travail considérable qui a été fait par nos deux développeurs français sur cette version, à savoir Antoine Pitrou et Victor Stinner. Et en plus, ils lisent linuxfr !

    Petite question sur le yield from: est-ce que c'est juste de la simplification de syntaxe, ou est-ce que on peut en attendre des légers gains de vitesse si on l'utilise par rapport à l'ancien idiome ?

  • # strings: Optimisation mémoire vs cpu?

    Posté par  . Évalué à 2.

    L'optimisation en occupation mémoire des chaînes de caractères n'a-t-elle pas un impact en performance cpu?

    Par exmple il y a probablement plus de conversions à la volée maintenant lorsqu'on itère sur les caractères non?
    Ou encore la concaténation de chaînes stockées sur différentes tailles de caractères…

    Y a-t-il des benchmarks sur ce point?

    • [^] # Re: strings: Optimisation mémoire vs cpu?

      Posté par  (site web personnel) . Évalué à 2. Dernière modification le 03 octobre 2012 à 17:35.

      Je pense que toutes les chaînes sont probablement codées en interne dans un format bien défini (je veux dire, choisi une fois pour toutes), il n'y a donc pas de conversion à la volée en lecture des caractères (hormis du padding).

      L'expression latin1 ou latin9 du texte signifie probablement que les caractères sont ceux du latin1 ou latin9, pas que la chaîne et codée en interne dans l'un ou l'autre de ces codages.

      Enfin, comme Python est plutôt un langage de haut niveau, je suspecte la concaténation des chaînes de se faire en temps constant, sans copie de caractères, jsute en se souvenant qu'après la chaîne a il y a la cahine b. Cela n'est possible que parceque les chaînes sont constantes, et signifie que la lecture des caractères se fait avec une indirection.

      • [^] # Re: strings: Optimisation mémoire vs cpu?

        Posté par  . Évalué à 2.

        D'après la PEP-393 il y a bien plusieurs représentations possibles de la string en interne.
        Cependant ça concerne uniquement la représentation unicode. La PEP parle d'ascii car c'est un sous ensemble de l'UTF-8: toute chaîne de caractère ascii peut être lue comme une chaîne UTF-8.

        Il y a donc bien une conversion à la volée des caractères entre l'encodage interne qui peut être de l'UTF-8, UTF-16 ou UTF-32, et la représentation publique, au moins dans les cas où on accède aux caractères directement (ils sont convertis en code-point unicode). Cela dit cette conversion était aussi faite avant.

        Pour la concaténation effectivement je ne sais pas si c'est réellement un problème.

        Cependant dans la PEP ils précisent:
        > A new function PyUnicode_AsUTF8 is provided to access the UTF-8 representation. It is thus identical to the existing _PyUnicode_AsString, which is removed. The function will compute the utf8 representation when first called. Since this representation will consume memory until the string object is released, applications should use the existing PyUnicode_AsUTF8String where possible (which generates a new string object every time). APIs that implicitly converts a string to a char* (such as the ParseTuple functions) will use PyUnicode_AsUTF8 to compute a conversion.

        Ce qui veut bien dire qu'il y a des méthodes utilisées qui font de la conversion à la volée.
        Cf aussi la liste des fonctions et macros de leur nouvelle API.

        • [^] # Re: strings: Optimisation mémoire vs cpu?

          Posté par  (site web personnel) . Évalué à 2.

          Il y a donc bien une conversion à la volée des caractères entre l'encodage interne qui peut être de l'UTF-8, UTF-16 ou UTF-32

          Le choix de UTF-8 16 ou 32 pour la représentation interne est fait pour que tu n'utilises jamais un codage multi mot (le mot fait 8 bits en UTF-8, 16 bits en UTF-16 et 32 bits en UTF-32): la conversion en question est juste d'ajouter les bits nuls manquant à tes points unicode. Je ne parlerais pas vraiment de conversion mais plutôt de convention pour accéder à la mémoire. (Au niveau assembleur, tu fais xor eax, eax pour annuler eax, puis tu choisis de lire ton caractère de 8 16 ou 32 bits en faisant un mov vers ah, ax ou eax et puis c'est tout.)

          A new function PyUnicode_AsUTF8 is provided to access the UTF-8 representation. It is thus identical to the existing _PyUnicode_AsString, which is removed. The function will compute the utf8 representation when first called.

          Je ne sais pas très bien ce que tu veux dire par «à la volée» mais cela me semble raisonnable qu'une fonction explicitement appelée déclenche un calcul.

    • [^] # Re: strings: Optimisation mémoire vs cpu?

      Posté par  . Évalué à 5. Dernière modification le 03 octobre 2012 à 20:29.

      Par exmple il y a probablement plus de conversions à la volée maintenant lorsqu'on itère sur les caractères non?

      Itérer sur les caractères est une opération triviale et, dans ce cas, c'est la boucle d'évaluation de CPython qui sera le facteur dominant.

      Par contre, là où ça peut être plus lent, c'est dans certaines créations de chaînes en combinant des chaînes utilisant des représentations différentes (par exemple : une concaténation, ou bien un appel à la méthode str.replace()). Cela ne se remarquera vraiment que sur des chaînes très longues, donc pas les cas les plus courants.

      (en contrepartie, il y a aussi certaines opérations qui deviennent plus rapides, par exemple décoder en utf-8 une chaîne d'octets qui s'avérerait être purement ASCII : ce cas est optimisé comme un simple memcpy())

    • [^] # Re: strings: Optimisation mémoire vs cpu?

      Posté par  (site web personnel) . Évalué à 7.

      L'optimisation en occupation mémoire des chaînes de caractères n'a-t-elle pas un impact en performance cpu?

      Côté positif : certaines opérations sont beaucoup plus rapide, notamment quand on manipule des chaînes de caractère "ASCII" :
      http://docs.python.org/dev/whatsnew/3.3.html#optimizations

      En gros : copier N caractères ASCII (stockés dans le format "UCS-1") nécessite de copier N octets, alors que copier N caractères stockés dans le format UCS-4 (Python 3.2 sous Linux) nécessite de copier 4*N octets. Par exemple, str[a:b] copie des caractères. Et comme l'a écrit Antoine : encoder une chaîne Unicode "de type ASCII" en UTF-8 revient simplement à faire un "memcpy" (en gros), ce qui est ultra rapide (comparé à l'encodeur de Python 2.7 et 3.2).

      Côté négatif : les opérations manipulant des chaînes utilisant différents formats nécessitent de convertir les chaînes vers le même format. Par exemple, "10€".replace("", " ") nécessite de convertir "_" du format UCS-1 au format UCS-2. Idem pour "10 " + "€".

      Créer une chaîne de caractère nécessite de connaître le caractère "maximum" (code Unicode le plus grand), ce qui nécessite de lire l'ensemble des caractères de la chaîne. Cette opération est coûteuse.

      Le bilan est mitigé car certaines opérations sont plus lentes, mais d'un autre, certaines fonctions ont été optimisées. Dans le meilleur des cas, certaines opérations Unicode avec Python 3.3 sont désormais plus rapides que ces opérations sur des octets avec Python 2.7 !

      Je ne connais pas de benchmark "global". Il existe divers micro-benchmarks qui ne sont pas représentatifs. En tout cas, il est sûr que la consommation mémoire est bien meilleure !

  • # Packaging

    Posté par  . Évalué à 3.

    Il n'était pas sensé y avoir des nouveautés sur le packaging.
    J'ai vu lu quelques truc sur sujet mais j'avoue ne pas trop savoir où cela va …

  • # Concertant l'empaquetage (PEP 420)

    Posté par  . Évalué à 6.

    Il est dit dans la dépêche:
    « Un module Python, sous forme de répertoire, n’a plus besoin de la présence d’un fichier __init__.py en son sein pour obtenir le statut de module. De plus, il peut être réparti sur plusieurs dossiers. »

    Je pense que c'est une erreur, l'auteur a certainement voulu parler de package. Ajourd'hui un package est un répertoire contenant un fichier __init__.py (qui peut être vide), et selon la PEP 420 les packages peuvent maintenant être répartis sur plusieurs répertoires.

    Le module c'est le fichier .py

Suivre le flux des commentaires

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