Python 3.4 est sorti avec 7 nouveaux modules

Posté par (page perso) . Édité par Davy Defaud, Benoît Sibaud, Nils Ratusznik, BAud, NeoX, Xavier Claude, palm123, Nonolapéro, jihele, Philippe F et tuiu pol. Modéré par tuiu pol. Licence CC by-sa
Tags : aucun
75
19
mar.
2014
Python

En termes de nouveautés, Python 3.4 est la version de Python qui en apporte le plus ! Il n’y a pas moins de 7 nouveaux modules entre Python 3.4 et 3.3 (séparés de 18 mois), tandis qu’entre Python 3.3 et Python 2.7 (séparés de 27 mois) il y en a huit. En termes de propositions d’améliorations de Python, 14 PEP (Python Enhancement Proposals) ont été implémentées dans Python 3.4. Cette version donne un sérieux coup de vieux à Python 2.7. La 2e partie de la dépêche détaille les principales nouveautés et la manière dont Python est développé.

Mon article Why should OpenStack move to Python 3 right now?, cité ci‐dessous, explique pourquoi Python 2 est désuet et pourquoi vous devez porter dès maintenant vos applications sur Python 3. L’article a été écrit pour le projet OpenStack mais reste général.

Sommaire

Nouveautés de Python 3.4

7 nouveaux modules

asyncio : nouveau module de programmation asynchrone, PEP 3156

Le module asyncio est une boucle d’événements permettant de gérer des événements de types différents dans un unique thread : sockets (TCP, UDP, SSL), signaux UNIX, processus, primitives de synchronisation, etc. Bien que le cœur d’asyncio utilise des callbacks, la programmation se fait essentiellement avec des co‐routines. Une co‐routine est une fonction qui peut être mise en « pause » explicitement avec le mot clé yield. Pour être précis, asyncio utilise la nouvelle expression yield from de Python 3.3 qui est plus performante que yield. Le résultat de la co‐routine est renvoyé par un classique return result (autre nouveauté de Python 3.3, return ne pouvait pas être utilisé dans une co‐routine avant). Voici un exemple de « Hello World » asyncio utilisant une co‐routine :

import asyncio

@asyncio.coroutine
def greet_every_two_seconds():
    while True:
        print('Hello World')
        yield from asyncio.sleep(2)   # <~~ la magie opère ici

loop = asyncio.get_event_loop()
loop.run_until_complete(greet_every_two_seconds())

Pour vous faire une idée de l’API choisie, je vous conseille de consulter la documentation du module asyncio et notamment les exemples :

Pour une présentation plus générale et plus d’information, consultez la liste des conférences sur asyncio.

Pour mon travail chez eNovance, j’ai rétroporté asyncio pour Python 2 dans un nouveau projet appelé Trollius. La raison est que je souhaite remplacer eventlet par Trollius dans le projet OpenStack (en bref : un « petit » projet Python anodin de 2,5 millions de lignes, utilisé dans « le cloud »), en partie pour porter OpenStack sur Python 3. Mon article Use the new asyncio module and Trollius in OpenStack explique tout cela en détails.

ensurepip

Installeur du programme pip (et de ses dépendances), PEP 453. L’outil pip devient le gestionnaire de modules de référence pour Python. Le module ensurepip permet notamment d’installer pip lors de la création d’un nouvel environnement virtuel avec le module venv. Lire aussi Rationalizing Python packaging sur LWN.

enum : prise en charge des types d’énumération, PEP 435

Le module enum fournit une implémentation standard de types énumérés, permettant aux autres modules (tels que socket) de proposer des messages d’erreur plus explicites, et de faciliter le débogage en remplaçant les constantes opaques avec des valeurs énumérées rétro‐compatibles. Par exemple, print(socket.socket().family) donne AddressFamily.AF_INET au lieu de « 2 ».

Ce nouveau module a fait l’objet d’un article An “enum” for Python 3 sur le site LWN.

pathlib : API orientée objet de manipulation de chemins du système de fichiers, PEP 428

selectors : multiplexage d’entrées‐sorties haut niveau et efficace, basé sur les primitives du module select, fait parti de la PEP 3156

statistics : fonctions pour calculer des statistiques mathématiques de données numériques, PEP 450

tracemalloc : tracer les allocations mémoires de Python, PEP 454

Il existe plusieurs outils pour calculer l’utilisation mémoire d’une application Python, dont notamment Heapy, Pympler et Melia. Le principal défaut de ces outils est qu’ils groupent les allocations selon le type d’objet : quand la majorité de la mémoire est utilisée par des types très courants comme str ou tuple, il est très difficile de retrouver la partie du code comportant une fuite de mémoire.

Le nouveau module tracemalloc prend le problème à l’envers. Plutôt que de partir des objets haut niveau (en parcourant les structures du ramasse‐miettes, module gc), tracemalloc se greffe sur l’allocateur mémoire bas niveau pour tracer les allocations mémoire de Python. tracemalloc utilise ensuite les structures de Python pour reconstituer la pile d’appel où l’allocation a eu lieu et l’associe au bloc mémoire alloué.

Avec ces informations, tracemalloc permet de :

  • fournir la pile d’appel où un objet Python a été alloué ;
  • calculer des statistiques par fichier, par numéro de ligne ou par pile d’appel : taille totale, nombre et taille moyenne des blocs alloués ;
  • calculer la différence entre deux instantanés (snapshots) pour détecter des fuites mémoires.

L’interface graphique [tracemallocqt](https://bitbucket.org/haypo/tracemallocqt) permet alors d’analyser finement ces données : filtrage, vue cumulative, groupage des allocations par fichier, ligne ou pile d’appel, comparaison deux instantanés, etc.

Un paquet rétro‐porté est disponible pour Python 2.5-3.3 : pytracemalloc. Il nécessite en revanche l’application d’un correctif, puis de recompiler Python.

Voir aussi la conférence que j’ai donnée à Pycon FR 2013 à Strasbourg sur tracemalloc : support PDF et enregistrement vidéo. Je donne également une conférence le mois prochain à Pycon Montréal 2014 sur le même sujet.

Nouvelles fonctionnalités

  • Les fichiers et sockets nouvellement créés sont marqués comme « non héritables » (PEP 446) : ceci évite de passer des fichiers et sockets aux processus fils, ce qui était la cause de nombreux problèmes et failles de sécurité listés dans la PEP. Ce changement peut casser la compatibilité ascendante, mais c’est un choix pour le bien de l’humanité : « We are aware of the code breakage this is likely to cause, and doing it anyway for the good of mankind. » (extrait de la PEP).
  • Nouvelle option en ligne de commande -I (isolate) pour lancer Python dans un mode isolé du système.
  • Amélioration de la gestion des codecs qui ne sont pas des codages de texte (ex : base64 et rot13).
  • Nouveau type ModuleSpec pour le système d’importation, PEP 451.
  • Le format de sérialisation marshal est plus compact et plus efficace.
  • La complétion des commandes par la touche de tabulation est maintenant activée par défaut dans l’interpréteur interactif. Par exemple, pri<TAB> est remplacé par print(.

Améliorations significatives de modules

  • single‐dispatch générique pour les fonctions dans functools, PEP 443 ;
  • nouveau protocole (quatrième) de sérialisation pour le module pickle (PEP 3154) : plus compact et permetant de sérialiser des objets qui ne pouvaient pas l’être avec Python 3.3 ;
  • le module multiprocessing a une nouvelle option pour éviter d’utiliser os.fork() sous UNIX (voir multiprocessing.set_start_method()) ;
  • le module email a un nouveau sous‐module contentmanager et une nouvelle sous‐classe de Message (EmailMessage) qui simplifient la gestion MIME ;
  • les modules inspect et pydoc sont désormais capables de faire de l’introspection de manière correcte sur une plus grande variété d’objets « callables » (qu’on peut appeler, comme une fonction), ce qui améliore la sortie de la commande help() dans l’interpréteur interactif de Python ;
  • l’API du module ipaddress a été déclarée stable.

Renforcement de la sécurité

  • Nouvelle fonction de hachage sûre utilisée par défaut, nommée SipHash (PEP 456), dont on peut lire des détails dans Python adopts SipHash sur LWN ;
  • les fichiers et sockets nouvellement créés sont marqués comme « non héritables » (PEP 446) ;
  • nouvelle option en ligne de commande -I pour lancer Python dans un mode isolé du système ;
  • le module multiprocessing a une nouvelle option pour éviter d’utiliser os.fork() sous UNIX : les modes spawn et forkserver sont plus sûrs, car ils évitent de partager des données avec les processus fils. Sous Windows, les processus fils n’héritent plus de tous les handles héritables du parent, uniquement ceux qui sont nécessaires ;
  • nouvelle fonction hashlib.pbkdf2_hmac(), offrant la 2e fonction de dérivation de clé basée sur un mot de passe de PKCS#5 : PBKDF2 ;
  • prise en charge des versions 1.1 et 1.2 de TLS par le module ssl ;
  • possibilité de récupérer les certificats depuis les dépôts de certificats Windows par le module ssl ;
  • le module ssl côté serveur gère maintenant SNI (Server Name Indication) ;
  • la classe ssl.SSLContext a été largement améliorée ;
  • tous les modules de la bibliothèque standard qui gèrent SSL prennent maintenant en compte la validation du certificat serveur, y compris la validation du nom d’hôte (ssl.match_hostname()) et la vérification de la listes de révocation de certificats (Certificate Revocation Lists, voir ssl.SSLContext.load_verify_locations()) : ceci veut dire que c’est maintenant possible en écrivant le code approprié, mais la validation demeure désactivée par défaut pour des raisons de compatibilité ascendante et de simplicité d’utilisation (Cf. Python, SSL/TLS certificates and default validation sur LWN).

Amélioration de l’implémentation CPython

  • Safe object finalization (PEP 442) : les objets ayant un destructeur (méthode __del__) peuvent maintenant être détruits par le ramasse‐miettes quand ils font partie d’un cycle de référence (ensemble d’objets se référençant entre eux créant un cycle) ;
  • dans la plupart des cas, les variables globales d’un module ne sont plus mises à None à la fin de l’exécution de Python ;
  • les allocateurs mémoires sont désormais configurables, PEP 445 ;
  • The Argument Clinic DSL (PEP 436) offre une introspection complète des fonctions et méthodes implémentées en C. Seule une partie des fonctions C ont été converties vers Argument Clinic, le travail sera terminé dans Python 3.5.

Autres changements

Lisez What’s New in Python 3.4 (lien donné plus haut) pour voir la liste complète des nouveautés et changements de Python 3.4.

Maturation de Python 3.4

La maturation d’une nouvelle version majeure de Python prend de 18 à 20 mois. Pour Python 3.4, le développement a été programmé par la PEP 429 : Python 3.4 Release Schedule. Alors qu’initialement la date de sortie était prévue pour le 22 février 2014, il a été choisi de repousser la sortie pour corriger les bogues majeurs, plutôt que de publier une version boguée.

Le release manager de Python 3.4, Larry Hastings, a eu beaucoup de travail ces deux derniers mois pour canaliser les développeurs et focaliser le développement sur la correction de bogues. Comme d’habitude, l’ajout de nouvelles fonctionnalités était proscrit pendant deux mois dans la branche de développement principale (« default »). Entre la première version release candidate et la version finale, Larry a choisi de créer une branche privée et de choisir quels commits de la branche default méritaient ou non de faire partie de la future version finale. Ses choix ont été critiqués, mais Larry a tenu bon et a réussi à publier une nouvelle finale !

Python Enhancement Proposals (PEP)

L’ajout d’un nouveau module, les changements touchant au cœur de Python et autres changements majeurs exigent d’écrire une PEP (Python Enhancement Proposal). Ce document sert de support pour discuter les changements et évite notamment qu’une discussion parte dans une boucle infinie (discussion qui repart régulièrement de zéro). Si des variantes sont proposées, elles doivent être notées dans la PEP, et si possible la PEP doit expliquer le choix de la solution proposée.

Une PEP provoque souvent une bonne centaine de messages sur les listes de discussion python-ideas ou python-dev, voire plusieurs centaines dans les pires cas. L’auteur de la PEP doit alors tenter d’adresser chaque commentaire et compléter sa PEP au fur et à mesure. Le processus est usant, mais, de mon expérience, l’API après discussion est très largement supérieure à l’API initialement proposée. Discuter une PEP, document de quelques pages, est plus facile que de discuter le correctif de son implémentation (jusqu’à plusieurs milliers de lignes).

Parfois, il y a deux solutions équivalentes qui présentent à peu près les mêmes avantages et inconvénients. Dans ce cas, le BDFL (Benevolent Dictator for Life) (Guido van Rossum) doit trancher entre les deux solutions. Guido van Rossum peut déléguer son rôle s’il n’est pas disponible ou n’est pas intéressé par le sujet.

Pour Python 3.4, les PEP enum, pathlib et asyncio ont provoqué des discussions enflammées avec plusieurs centaines de messages, mais le résultat est là : l’API a été éprouvée. Même si une PEP est refusée, le document en tant que tel devient de facto la référence sur le sujet. Si quelqu’un redemande la même fonctionnalité, la PEP sert d’argumentaire pour expliquer le rejet de la fonctionnalité.

Le processus de rédaction de la PEP garantit également que Python reste un langage cohérent et homogène. D’ailleurs, PHP a adopté un processus similaire depuis PHP 5.3 (PHP: Request for Comments).

Petite histoire de la création du module asyncio et du projet Tulip

Suite à une discussion intitulée « Quelle est la meilleure bibliothèque de programmation asynchrone en Python ? » sur la liste python-ideas, Guido van Rossum s’est mis dans la tête d’écrire la sienne (bah tiens, tant qu’à faire).

S’en est suivi une discussion fleuve sur les bibliothèques existantes, sur les fonctionnalités attendues d’une telle bibliothèque, sur les callbacks versus co‐routines versus Deferred (Twisted) versus Future, etc. Cette discussion a donné lieu à une PEP 3156 : « Asynchronous IO Support Rebooted: the “asyncio” Module », qui a mis plusieurs mois à être écrite.

Une fois que les bases ont été mises en place, Guido s’est attaqué à une implémentation pour Python 3.3 sous le nom Tulip (le nom du module Python étant asyncio). Les deux frameworks majeurs étant Twisted et Tornado, il a repris la première lettre « T » et a choisi le nom Tulip : référence à son pays d’origine, les Pays‐Bas ?

La PEP et l’implémentation ont bénéficié de critiques des auteurs des frameworks existants qui ont permis des les améliorer. Les auteurs de Twisted auraient voulu une API plus proche de Twisted, mais Guido a volontairement choisi une API différente, notamment pour la syntaxe des co‐routines.

Rétroportages

Le développement de la plupart des nouveaux modules de Python 3.4 a débuté sur une version plus ancienne de Python. Des rétroportages sont disponibles pour les nouveaux modules :

  • asyncio, selectors : trollius pour Python 2.6-3.3 ;
  • enum : enum34 pour Python 2.4-3.3 ;
  • pathlib : pathlib pour Python 2.7-3.3 ;
  • statistics : stats pour Python 3.1-3.3 ;
  • tracemalloc : pytracemalloc pour Python 2.5-3.3.

Pour la suite

Le mois prochain aura lieu Pycon Montréal 2014, rencontre mondiale Python regroupant plusieurs milliers de développeurs. Les nouveautés de Python 3.4 seront présentées, et les prochains développements seront discutés.

J’espère que les efforts sur la programmation asynchrone Python vont se concentrer sur asyncio, et que de plus en plus de modules vont être compatibles. Il existe des event loops asyncio pour greenlet, gevent, libuv, GLib, Tornado et 0MQ. Il existe des pilotes de base de données pour PostgreSQL, Redis, MongoDB et Memcached. Il existe des clients et serveurs HTTP, Web sockets, et un worker Gunicorn. Voir la page asyncio third party pour la liste complète, certains étant encore expérimentaux.

Bien sûr, l’essentiel des évolutions de Python se fait dans des modules externes. Le dépôt Python PyPI comporte à l’heure actuelle 41 181 paquets.

  • # A quand l'équivalent des symboles Ruby en Python ?

    Posté par . Évalué à 2.

    Ca c'est vraiment un truc qui manque en Python.

    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

      Posté par . Évalué à 2. Dernière modification le 19/03/14 à 11:54.

      Je ne comprend pas vraiment l’apport relativement à une bête string.

      (tu parles bien de :foo ?)

      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

        Posté par . Évalué à 3.

        Je ne comprend pas vraiment l’apport relativement à une bête string.

        Je ne le voyais pas non plus avant de le connaitre en Ruby, puis en Erlang avec les atoms qui sont plus ou moins la même chose, mais maintenant que je connais, ça me gène de devoir contourner ce manque avec des strings.

        Ca peut éviter par exemple les constructions que tu retrouves en C du style # define TRUC 0 alors qu'il n'y a pas de raison de lui attribuer une valeur. Ca permet également de ne pas à avoir à manipuler des strings alors que ce n'est pas utile. Je vais essayer de retrouver un exemple ou j'ai senti le manque de symbol en python (mais je ne suis pas sur de l'avoir encore sous la main, j'ai changé de mission entre temps).

        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

          Posté par . Évalué à 4.

          Le problème du C c'est que quand tu imprime un enum tu te retrouve avec un entier alors que dans ton programme tu manipules un symbole, c'est pénible a lire ou a gérer pour éviter ça, mais vu qu'avec les enums Python ce n'est pas le cas je ne suis pas sûr que les atom apportent grand chose par rapport aux enum..

          • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

            Posté par . Évalué à 2. Dernière modification le 19/03/14 à 15:26.

            Qu'est-ce qu'un enum en Python ? c'est ni plus ni moins qu'une structure associative. Pour t'aider à comprendre : suppose qu'en Python tu dois représenter l'état d'une LED : allumé et éteint. Comment fais-tu ?

            • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

              Posté par . Évalué à 2.

              Qu'est-ce qu'un enum en Python ? c'est ni plus ni moins qu'une structure associative.

              Certes et alors?
              Je ne comprends pas ta question, ni le rapport avec la "nécessité" d'avoir les symboles en plus des enums "à la Python".

              • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                Posté par . Évalué à 1.

                Certes et alors?
                Je ne comprends pas ta question, ni le rapport avec la "nécessité" d'avoir les symboles en plus des enums "à la Python".

                OK, je viens de voir tes messages suivant et j'ai compris: ton problème est que l'utilisation des enums comme des symboles viole la règle DRY(Don't Repeat Yourself) (enum TOTO='TOTO')

                Tu aurais expliqué ça dès le début, ça aurait été plus clair..
                Ceci dit, je n'aime pas trop les symboles car ils sont préfixés par :, #, \ (dépend du langage), alors que les enums non..

                Tant qu'à rajouter une notation magique pour éviter les répétitions, moi j'aurais fait enum TOTO@ (équivalent de enum TOTO='TOTO') et hop, le moche symbole ne se voit que dans la déclaration de l'enum, est-ce que ça te conviendrait maintenant?

                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                  Posté par . Évalué à 2. Dernière modification le 19/03/14 à 15:52.

                  OK, je viens de voir tes messages suivant et j'ai compris: ton problème est que l'utilisation des enums comme des symboles viole la règle DRY(Don't Repeat Yourself) (enum TOTO='TOTO')

                  Entre autres … :)

                  Tu aurais expliqué ça dès le début, ça aurait été plus clair..

                  Je t'avoue que le symbole est un concept que j'ai eu du mal à comprendre quand j'ai commencé le Ruby, mais qui me parait tellement évident aujourd'hui que j'ai du mal à l'expliquer.

                  Ceci dit, je n'aime pas trop les symboles car ils sont préfixés par :, #, \ (dépend du langage), alors que les enums non.

                  Tant qu'à rajouter une notation magique pour éviter les répétitions, moi j'aurais fait enum TOTO@ (équivalent de enum TOTO='TOTO') et hop, le moche symbole ne se voit que dans la déclaration de l'enum, est-ce que ça te conviendrait maintenant?

                  Non parce que tu utilises un objet associatif pour une représentation qui ne l'est pas. L'avantage du symbole est qu'il ne représenter que lui même. Tu n'as pas d'association arbitraire à déclarer nulle part.

                  En Erlang par exemple, tu différencies l'équivalent du symbole (atom) car il commence en minuscule, contrairement à une variable qui elle commence par une majuscule.

                  A la limite, tu pourrais je pense utiliser une chaine de caractère là ou on utilise le symbole en ruby, par contre quelque part ça prête à confusion dans le code, vu que le rôle des deux n'est pas tout à fait le même

              • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                Posté par . Évalué à 2.

                Je ne comprends pas ta question

                Je vais en poser une autre alors: supposons que tu aies un objet représentant une commande de clignotant dans une voiture : ton clignotant peut être dans 3 positions : gauche, droit ou éteint. Comment représenterais-tu celà en Python ?

                ni le rapport avec la "nécessité" d'avoir les symboles en plus des enums "à la Python".

                Peut-être comprendras-tu mieux après.

                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                  ton clignotant peut être dans 3 positions : gauche, droit ou éteint. Comment représenterais-tu celà en Python ?

                  Un peu comme en C ?

                  from enum import Enum
                  class Position(Enum):
                     gauche = 1
                     droit = 2
                     eteint = 3
                  

                  En Ruby ça donnerait quoi ? Il n'y aurait pas besoin d'enum et possibilité de mettre :gauche, :droit et :eteint ?

                  Au niveau du typage, ça donnerait quoi ?

                  • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                    Posté par . Évalué à 1.

                    En Ruby ça donnerait quoi ? Il n'y aurait pas besoin d'enum et possibilité de mettre :gauche, :droit et :eteint ?

                    Oui.

                    Au niveau du typage, ça donnerait quoi ?

                    Un symbole qui est un type à part entière.

                    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                      Posté par . Évalué à 8.

                      Un symbole qui est un type à part entière.

                      Tous les symboles ont le même type, ce n'est pas la même chose que de définir un type d'énumération distinct par usage.

                      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                        En fait, Python supporte les symboles en se limitant à des caractères hexa :D:

                        symbol = 0xdeadbeef
                        

                        Suffirait d'ajouter une nouvelle syntaxe pour exprimer des nombres dans une base 62 (26 * 2 + 10) et ça irait :). Bon, idéalement, on inventerait un nouveau type pour ça quand même.

                        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                          Non ça ne marche pas (mais c'était drôle quand même). Il se trouve que dans CPython (mais a priori c'est une question d'implémentation, ce n'est pas portable), les entiers jusqu'à 256 sont des singletons (ils sont pré-alloués en plus me semble-t-il). Chez moi (Python 2.7.6):

                          > a = 256
                          > b = 256
                          > a is b
                          True

                          Mais

                          > a = 257
                          > b = 257
                          > a is b
                          False

                          Donc on n'a pas "==" et "is" qui sont équivalents de manière général (et donc pas avec "0xdeadbeef" en particulier).

                          • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                            Je ne pensais pas à utiliser is en fait, juste ==. Je voyais les symboles comme des int avec des lettres tout simplement. Et donc tout comme avec les int, je n'utilise pas is.

                            Mais sinon je savais pas pour cette histoire de singletons. J'ai du mal à voir l'intérêt par contre.

                            • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                              J'ai du mal à voir l'intérêt par contre.

                              C'est un détail interne d'implémentation. Les entiers 0 à 256 (et -1 à -127 je crois) sont très couramment utilisés, et il est plus efficace de les pré-allouer et de ne faire que du comptage de références plutôt que d'allouer/libérer à chaque fois un objet entier correspondant.

                              Mais c'est vraiment de la cuisine interne, on ne compare jamais deux entiers avec is.

                              Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

                              • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                                Oui j'avais bien compris mais j'avais oublié un instant que un 'int' n'était pas juste une valeur mais un objet avec des méthodes. D'où l'intérêt d'éviter d'en faire des doublons. Pour la peine, est-ce qu'ils n'auraient pas gagné en perf en faisant une distinction entre int et Integer comme en Java ?

                                >>> a = 42
                                >>> a.__dir__()
                                ['__rfloordiv__', '__setattr__', 'conjugate', '__floordiv__', '__xor__', '__str__', '__bool__', '__repr__', '__sub__', '__rdivmod__', '__lshift__', '__format__', '__reduce_ex__', '__hash__', '__divmod__', '__gt__', '__rsub__', '__pow__', 'from_bytes', 'numerator', '__ne__', '__rmod__', '__le__', '__ceil__', '__or__', '__lt__', '__rshift__', '__floor__', '__int__', '__add__', '__init__', '__rrshift__', '__sizeof__', '__delattr__', '__reduce__', '__rxor__', '__ge__', '__round__', 'real', '__neg__', '__rmul__', '__index__', '__radd__', '__subclasshook__', '__doc__', '__new__', '__mul__', '__ror__', '__and__', 'to_bytes', '__rand__', 'denominator', 'imag', '__getnewargs__', '__getattribute__', '__float__', '__truediv__', '__class__', 'bit_length', '__rtruediv__', '__abs__', '__invert__', '__rlshift__', '__pos__', '__rpow__', '__mod__', '__dir__', '__eq__', '__trunc__']
                                
                                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                                  Pour la peine, est-ce qu'ils n'auraient pas gagné en perf en faisant une distinction entre int et Integer comme en Java ?

                                  Ça marche en Java (et C#) grâce au typage statique ; le langage sait s'il faut convertir un int en Integer (ou l'inverse) car il connaît le type des variables et celui des paramètres des méthodes. Mais comment faire en Python ? Ta fonction "def foo(a): […]" comment peut elle savoir si elle reçoit de la part de l'appelant un int ou un *PyObject (au sens C) ? Tout repose sur le fait que les variables sont toutes des *PyObjects, et qu'ensuite on applique le duck typing.

                                  A noter quand même :

                                  • Dans CPython, y a pas mal d'endroits où la VM prend des raccourcis quand elle rencontre des types de base. Par exemple avec "if a:", la méthode __nonzero__/__bool__ de "a" n'est pas appelée en cherchant dans la virtual table lorsque Python s'aperçoit que "a" est un *PyInteger ou une *PyList par exemple, car en pratique on appelle rarement "if" sur des instances classes utilisateur. Python reste évidemment lent, mais il le serait beaucoup plus s'il était codé naïvement.
                                  • PyPy est capable de générer du code machine travaillant avec des simples int lorsqu'il s'aperçoit que c'est possible et pertinent ; par exemple il va utiliser une version spécialisée de liste si elle ne contient que des *PyInteger.
      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

        Posté par . Évalué à 3. Dernière modification le 19/03/14 à 23:36.

        Let me Google that for you

        TL,DR : ce sont des identifiants. Et ils sont toujours alloués pendant que ton programme tourne, donc c'est à utiliser avec modération.

        "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

      Posté par . Évalué à 3.

      Une petite explication, un exemple ou un lien sur les symboles de ruby serait bienvenue :)

      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

        Posté par . Évalué à 3. Dernière modification le 19/03/14 à 12:03.

        C’est en gros une string, notée :foo au lieu de "foo", avec juste une ou deux différences avec une string normale:

        • Seuls les identifiants (au sens nom de variable) sont possibles
        • Le type est Symbol, pas String
        • Deux symbole identiques ont la garantie d’être portés par le même objet (en termes Python, pour les symboles, == implique is)
      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

        Posté par . Évalué à 2.

      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

        Posté par . Évalué à 2.

        http://www-etud.iro.umontreal.ca/~dift2035/e2009/cours/introduction_a_ruby_reduite_v0.3.pdf

        Où sont utilisés les symboles ?
        [ ... ]
        Noms de méthodes 
        Pour faire référence au nom d’une méthode, on peut
        utiliser un symbole Car en définissant une méthode, un symbole est créé
        et porte le même nom que la méthode en question
        

        L'un des intérêts en ruby est qu'on peut appeler des méthodes dynamiquement sans faire appel à Eval : c'est dans un cas de ce genre que ceux-ci m'ont manqués.

        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

          Posté par . Évalué à 4. Dernière modification le 19/03/14 à 12:26.

          L'un des intérêts en ruby est qu'on peut appeler des méthodes dynamiquement sans faire appel à Eval : c'est dans un cas de ce genre que ceux-ci m'ont manqués.

          Faisable en Python sans symboles :

          method = "strip"
          obj = " foo "
          print(getattr(obj, method)())
          • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

            Posté par . Évalué à 0.

            D'après la doc python :

            getattr(object, name[, default])

            Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.
            

            Il semble (mais je peux me tromper) que ceci ne concerne que les attributs et non les méthodes …

            • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

              Les méthodes sont des attributs !

              • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                Posté par . Évalué à 0.

                As-tu essayé le code donné plus haut ?

                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                  Posté par . Évalué à 4. Dernière modification le 19/03/14 à 13:28.

                  Pas toi ? :)

                  Python 3.3.5 (default, Mar 10 2014, 03:21:31) 
                  [GCC 4.8.2 20140206 (prerelease)] on linux
                  Type "help", "copyright", "credits" or "license" for more information.
                  >>> method = "strip"
                  >>> obj = " foo "
                  >>> print(getattr(obj, method)())
                  foo
                  

                  François a raison, en Python les méthodes sont des attributs comme les autres. Tu peux même faire des trucs rigolo comme

                  myobj.square = lambda (self): self*self
                  myobj.square()
                  • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                    Posté par . Évalué à 1.

                    Chez moi ça n'a pas marché (voir mon autre commentaire un peu plus haut). Mais je viens de voir que je suis en Python 2.7, pas en Python3. Peut-être pour ça ?

                    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                      Posté par . Évalué à 4.

                      Ça marche aussi sous Python 2.7 pourtant:

                      Python 2.7.6 (default, Feb 26 2014, 12:07:17) 
                      [GCC 4.8.2 20140206 (prerelease)] on linux2
                      Type "help", "copyright", "credits" or "license" for more information.
                      >>> method = "strip"
                      >>> obj = " foo "
                      >>> print(getattr(obj, method)())
                      foo
                      
                      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                        Posté par . Évalué à 1.

                        Je viens de réesayer, et ça marche. Je crois que j'ai pris un espace en trop lors du copier/coller. Mais ce que tu fais là me semble bizarre : lorsque j'ai essayer de le transposer à un vrai exemple dans un script (comme celui plus haut), j'ai obtenu une erreur indiquant que l'objet str n'avait pas de méthode foo.

                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                  Posté par . Évalué à 2.

                  Bon, j'ai testé, ça marche, mais il y a une ou deux coquilles dans le code fourni à l'origine qui m'ont induit en erreur : le premier paramètre ne doit pas être une chaine :

                  #!/usr/bin/python
                  
                  class MyObject:
                  
                      def __init__(self):
                          self.a=20
                      def method1(self):
                          return 10
                  
                  O=MyObject()
                  
                  print(O.method1())
                  
                  attr=" a "
                  method = "method1"
                  obj = " MyObject "
                  print (getattr(O, "a"))
                  print (getattr(O, method)())
                  

                  à l'exécution$ ./toto.py

                  10
                  20
                  10
                  

                  J'essaierai de retrouver mon exemple car il me semble que c'était un peu plus subtil. Celà dit merci pour l'astuce.

                  • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                    Posté par . Évalué à 1. Dernière modification le 19/03/14 à 14:35.

                    Bon, voilà un autre exemple que j'a&i eu à traiter il y a peu :

                    J'utilise le module logging.

                    Je veux parser dans 4 fichiers différents les messages de type INFO, WARNING, ERROR, et DEBUG.

                    Je veux nommer mes fichiers monprog-.log avec "level" correspondant à info, warning, error ou debug.

                    En ruby, la façon générale de faire est de définir un symbole :ERROR :WARNING :INFO et :DEBUG

                    J'aurais donc un truc du genre (si les symboles existaient comme en Ruby):

                    mylogger=logging.getLogger(name)
                    
                    for i in (:ERROR, :WARNING, :INFO, :DEBUG) :
                      FILENAME="monprog"+'-'+(i.to_str()).lower()+".log"
                    
                      h=logging.handlers.RotatingFileHandler(
                                FILENAME, backupCount=5)
                      h.doRollover()
                      h.setLevel(i)
                      mylogger.addHandler(ch)
                    

                    Or actuellement, les levels INFO, WARNING, DEBUG et ERROR soint implémentés ainsi :

                    ERROR = 40
                    WARNING = 30
                    INFO = 20
                    DEBUG = 10

                    Comment puis-je donc faire le même genre de chose sans utiliser un dictionnaire ?

                    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                      Posté par . Évalué à 3. Dernière modification le 19/03/14 à 14:50.

                      Je viens d'aller voir le module logger, et comme je le craignais, on a un truc affreux comme ça :

                      _levelNames = {
                          CRITICAL : 'CRITICAL',
                          ERROR : 'ERROR',
                          WARNING : 'WARNING',
                          INFO : 'INFO',
                          DEBUG : 'DEBUG',
                          NOTSET : 'NOTSET',
                          'CRITICAL' : CRITICAL,
                          'ERROR' : ERROR,
                          'WARN' : WARNING,
                          'WARNING' : WARNING,
                          'INFO' : INFO,
                          'DEBUG' : DEBUG,
                          'NOTSET' : NOTSET,
                      }
                      

                      avec plus loin ceci :

                      def getLevelName(level):
                          """
                          Return the textual representation of logging level 'level'.
                      
                          If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,
                          INFO, DEBUG) then you get the corresponding string. If you have
                          associated levels with names using addLevelName then the name you have
                          associated with 'level' is returned.
                      
                          If a numeric value corresponding to one of the defined levels is passed
                          in, the corresponding string representation is returned.
                      
                          Otherwise, the string "Level %s" % level is returned.
                          """
                          return _levelNames.get(level, ("Level %s" % level))
                      
                      def addLevelName(level, levelName):
                          """
                          Associate 'levelName' with 'level'.
                      
                          This is used when converting levels to text during message formatting.
                          """
                          _acquireLock()
                          try:    #unlikely to cause an exception, but you never know...
                              _levelNames[level] = levelName
                              _levelNames[levelName] = level
                          finally:
                              _releaseLock()
                      

                      Je trouve ça moche et inefficace. Voici donc un exemple précis ou les symboles simplifient la vie et la clarté. Et c'est à cause de ce genre de détails que je préfère Ruby à Python.

                    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                      Posté par . Évalué à 1.

                      Or actuellement, les levels INFO, WARNING, DEBUG et ERROR soint implémentés ainsi :

                      L'intérêt c'est d'avoir un ordre bien défini (ERROR est plus grand que WARNING, etc.).
                      Je ne vois pas le rapport avec les "symboles" Ruby, mais peut-être que quelque chose m'échappe.

                      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                        Posté par . Évalué à 2.

                        L'intérêt c'est d'avoir un ordre bien défini (ERROR est plus grand que WARNING, etc.)

                        Et pourquoi ? Personnellement, en tant qu'utilisateur de l'API j'en ai rien à faire non ? C'est du détail d'implémentation ça.

                        Je ne vois pas le rapport avec les "symboles" Ruby, mais peut-être que quelque chose m'échappe.

                        En ruby tu définis des symbole ERROR, WARNING INFO et DEBUG. Tu ne leur attribue aucune valeur correspndante : le symbole se suffit à lui même.

                        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                          Dans ce cas, présis, ça a un sens d'avoir un entier associé avec le niveau de log. Tu peux ainsi définir assez facilement la notion de "tous les messages avec un niveau de log supérieur à ERROR" (ERROR + FATAL), "tous les messages avec un niveau de log supérieur à INFO" ( = INFO + WARNING + ERROR + FATAL).

                          Cela dit, ton besoin d'un symbole abstrait (si je l'ai bien compris) est justement couvert par l'ajout du module Enum à Python 3.4 :

                          >>> from enum import Enum
                          >>> Animal = Enum('Animal', 'ant bee cat dog')
                          >>> myPet = Animal.ant
                          >>> yourPet = Animal.beee
                          Traceback (most recent call last):
                            File "<pyshell#7>", line 1, in <module>
                              yourPet = Animal.beee
                            File "C:\Python34\lib\enum.py", line 236, in __getattr__
                              raise AttributeError(name) from None
                          AttributeError: beee
                          >>> 
                          

                          Et tu gagnes en plus une vérification syntaxique à l'assignation de ta variable et non pas à son utilisation…

                          Pour reprendre ton exemple plus haut en ruby, par exemple, si tu remplaces :WARNING par :WAAAARNING, l'erreur ne sera visible que au niveau du h.setLevel(i) et pas lors de l'énumération des champs possibles.

                          Si Python utilisais un Enum pour gérer ça, tu aurais un logging.LogLevels = Enum('DEBUG', 'INFO', 'WARNING', 'ERROR' ) et tu pourrais faire :

                          for i in logging.LogLevels:
                              ...
                          

                          Mais globalement, si on regarde ça d'un peu plus haut, les différences sont globalement mineures et ne transforment pas massivement ni l'expressivité, ni la fonctionnalité dans un langage ou dans un autre.

                          Bref, c'est de l'enc******* de mouche .

                        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                          Posté par . Évalué à 2.

                          En ruby tu définis des symbole ERROR, WARNING INFO et DEBUG.

                          En Python tu peux faire exactement la même chose avec des chaînes de caractères. Le module logging a fait un choix différent, mais ça ne veut pas dire que ce n'est pas possible.

                          En d'autres termes, tes récriminations me semblent toujours sans fondement.

                          • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                            Posté par . Évalué à 3.

                            En Python tu peux faire exactement la même chose avec des chaînes de caractères. Le module logging a fait un choix différent, mais ça ne veut pas dire que ce n'est pas possible.

                            Ce n'est pas la première fois que je rencontre ce genre de cas de figure : avoir un type dédié permet de ne pas se poser de question lorsque tu rencontre une chaine de caractère, savoir si elle est utilisée comme symbole ou comme chaine. A la lecture c'est plus simple à comprendre.

                            C'est comme beaucoup de choses : on se dit qu'on en a pas besoin tant qu'on ne l'utilise pas, puis quand on se retrouve à l'utiliser on se rend compte après qu'il est difficile de s'en passer.

                            • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                              Je pense comprendre l'intérêt mais pour moi c'est quelque chose d'assez rare au final. En dehors de considérations de perf, je préfère l'usage d'un enum ou de constantes plutôt qu'un symbole. Pour moi c'est tout aussi clair sauf que si je fais une typo pour mon enum, je devrais avoir une erreur de syntaxe. Comment je peux être sûr avec un symbole ? Déjà que le principal reproche que je fais au python c'est de pouvoir écrire :

                              obj.totto = 42
                              

                              au lieu de

                              obj.toto = 42
                              

                              sans avoir d'erreur facilement visible. Si en plus on rajoute des symboles qui ne sont pas non plus vérifiables, je repasse au Java.

    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

      Puisque ça manque au Python, est-ce que tu peux donner un exemple concret où la notion de symbole apporterait quelque chose ? N'étant pas familier avec le Ruby, j'ai du mal à voir de quoi il s'agit. J'imagine que c'est différent des types énumérés ?

      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

        Bon, je viens de lire tous les commentaires à ce sujet. Ma conclusion est que ouais ça pourrait être sympa dans de rares cas. Mais franchement, on peut largement s'en passer. On perd encore plus en vérification syntaxique par rapport à un enum ou une constante. Et si on veut un truc qui s'en rapproche, on peut toujours utiliser directement des chaînes de caractère (modulo les perfs peut-être). De toute façon, il y a tellement peu d'exemples où ça change la vie…

        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

          modulo les perfs peut-être

          Les symboles Ruby sont des chaînes rendues explicitement "intern"—existant de façon unique—via une syntaxe spéciale. En Python l'optimisation faite sur les chaînes courtes litérales réalise la même chose de façon automatique (réutilisation du même objet pour représenter la même chaîne - les chaînes Python étant immutables ça ne pose aucun problème).

          Et pour tout ce qui serait issu de saisie ou lecture fichier, un simple appel à sys.intern() réalise l'opération.

          >>> s1 = 'truc'
          >>> s2 = 'truc'
          >>> s1 is s2
          True

          Vérification en utilisant deux modules:

          #m1.py
          s1 = 'toto'
          #m2.py
          s2 = 'toto'

          Utilisation des modules.

          >>> import m1,m2
          >>> m1.s1
          'toto'
          >>> m2.s2
          'toto'
          >>> m1.s1 is m2.s2
          True
          # Si on utilise autre chose que des litérales, il faut explicitement appeler intern()
          >>> s3 = input()
          toto
          >>> s3 is m2.s2
          False
          >>> import sys
          >>> s4 = sys.intern(s3)
          >>> s4 is m2.s2
          True

          Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

      Posté par . Évalué à 6.

      Après avoir lu tous les commentaires, je trouve que c'est une mauvaise solution à un vrai problème.

      Je suis d'accord que l'utilisation des string pour ça est très mauvaise, mais les symboles ne sont pas beaucoup mieux notamment parce qu'ils n'apportent rien en terme de typage et de sécurité.

      Tu parle des niveaux de log. Rien ne t'empêche de passer une mauvaise valeur. Tu ne peux pas non plus les énumérer.

      Le fait de pouvoir s'en servir pour appeler une méthode me semble aussi affreux.

      La bonne solution est simple, c'est une énumération. Celle du C++ est pittoresque, mais si tu regarde du coté de Java par exemple :

      public enum LogLevel {
          DEBUG, TRACE, INFO, WARNING, ERROR, FATAL;
      }

      Tu peux évidement critiquer la verbosité de java (mais c'est aussi possible en scala, clojure et pleins d'autres). Mais tu as quelque chose qui t'apporte fonctionnellement tout ce que tu cherche avec en plus un typage (ce qui permet de regrouper les valeurs). Bon après en java les enum peuvent en plus porter des données et du code, mais je trouve ça plutôt bien fait.

      Les enum de python doivent répondre à ton besoin.

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

        Posté par . Évalué à 3. Dernière modification le 20/03/14 à 22:08.

        Le fait de pouvoir s'en servir pour appeler une méthode me semble aussi affreux.

        Euh, c'est rien que de la méta-programmation (on peut aussi utiliser un string à la place), c'est pas cochon, ni interdit par la convention de Genève, je t'assure. ;-)

        Pour les symboles, ils sont aussi utilisés dans les hashs (dictionnaire clé/valeur), et parfois quand on veut donner plusieurs arguments à méthode.

        "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

          Posté par . Évalué à 2. Dernière modification le 20/03/14 à 22:11.

          Dans le lien ci-dessous, on utilise les hashs pour les méthodes avec des paramètres optionnels, et pour émuler des méthodes avec des paramètres nommés :
          http://ruby.about.com/od/advancedruby/qt/opthash.htm

          "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

          • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

            Pour un nombre variable de paramètres nommés, c'est standard en Python:

            def my_method(**opts):
                 # opts est un dictionnaire nom=>valeur
            
            my_method(a=3, y=7, nom='toto')

            Je ne pensais pas que Ruby nécessitait des hacks dans ce genre pour faire des choses aussi triviales.

            Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

            • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

              Posté par . Évalué à 2. Dernière modification le 20/03/14 à 23:12.

              Merci pour l'info sur Python.

              Pas mal le trololo à la fin. Mais le "hack" pour Ruby est trivial.

              De l'autre côté en Ruby il y a des symboles, les mots clés private/protected/public, les refinements, … ;-)

              "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

              • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                Appréciable, la page de De Python à Ruby, ça permet de voir les grosses différences. Certaines choses ne sont que syntaxiques, mais d'autres portent sur la sémantique, et là il y a vraiment des choix pour lesquels je préfère ce qui a été fait côté Python:

                • le transtypage vers les booléens [*].
                • les chaînes mutables (d'autres langages récents ont fait le même choix, pour moi c'est devenu quasi éliminatoire).
                • les appels de fonctions/méthodes sans parenthèses.

                Sinon, une question, la notation Ruby :b => 'this great' dans un appel de fonction, ça crée automatiquement un hash, même sans les accolades?

                [*] Quoi que, même pour Python, je préférerais presque, entre autre pour mes étudiants, qu'une expression booléenne soit explicite là où on en besoin d'un booléen (if… while…). Le transtypage implicite raccourcit l'écriture mais casse la sémantique.

                Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                  Posté par . Évalué à 2. Dernière modification le 21/03/14 à 07:04.

                  Sinon, une question, la notation Ruby :b => 'this great' dans un appel de fonction, ça crée automatiquement un hash, même sans les accolades?

                  Oui.

                  Quant aux chaînes mutables, si tu veux un truc non-mutable, les symboles sont là pour ça.

                  "Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)

                  • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                    Je veux des chaînes non mutables par défaut, comme le sont les int, bool, float… et str en Python, un bête type de base.

                    Ne pas avoir à considérer qu'une chaîne est ou pas utile ailleurs, que je peux ou pas la modifier, qu'il y a ou pas des conséquences, qu'il faut penser ou pas à travailler sur une copie.
                    Chaînes immutables = obligation d'en créer une nouvelle si on veut la modifier, pas d'effet de bord entre les fonctions ou entre les threads.

                    Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

                    • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                      Posté par . Évalué à 2.

                      Chaînes immutables = obligation d'en créer une nouvelle si on veut la modifier, pas d'effet de bord entre les fonctions ou entre les threads

                      Cet argument pourrait s’appliquer à tout objet…

                      • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                        Toutafé, et tu peux définir un objet dont aucune des méthodes ne modifie l'original. Après, on rentre dans d'autres paradigmes de programmation, plus fonctionnelle - mais Python reste pragmatique.

                        Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

                  • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

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

                    Q? est-ce qu'il y a une gestion mémoire (ramasse miette, comptage de réfs…) sur les symboles en ruby?

                    Python 3 - Apprendre à programmer en Python avec PyZo et Jupyter Notebook → https://www.dunod.com/sciences-techniques/python-3

                • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

                  Posté par . Évalué à 3.

                  Appréciable, la page de De Python à Ruby, ça permet de voir les grosses différences. Certaines choses ne sont que syntaxiques, mais d'autres portent sur la sémantique,

                  Ils comparent avec quelle version de Python?

                  Les classes old style et new style, ce n'est pas du Python < 3?

          • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

            Posté par . Évalué à 2.

            C'est typiquement tiré de perl ça.

            Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

        • [^] # Re: A quand l'équivalent des symboles Ruby en Python ?

          Posté par . Évalué à 4.

          Pour la métaprogrammation j'avais mal compris. Pour le reste c'est pas nécessaire ou du moins les enum le permettent avec les avantages que j'ai déjà décris, donc la question ce n'est pas quand est-ce que python aura des symboles, mais quand est-ce que ruby aura des enum si ce n'est pas encore le cas ?

          Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

  • # asyncio vous emmène vers Python 3

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

    asyncio, c'est vraiment la killer-feature de cette nouvelle version. Ca pourrait à lui seul justifier que des projets emprisonnés dans Python 2.7 passent en Python 3! Sauf que … il existe un backport Python 2 !

    Finalement, presque la totalité des goodies de la lib de Python 3.4 sont disponibles sous forme de backport pour des version inférieures, et notamment Python 2.7 . Et côté évolution du runtime ou du langage, les évolutions ont l'air utiles mais ont relativement peu de chances d'impacter le développeur python "moyen" qui ne pousse pas Python dans ses retranchements. Ah si quand même, les évolutions autour de SSL, va vaut le coup.

    • [^] # Re: asyncio vous emmène vers Python 3

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

      asyncio, c'est vraiment la killer-feature de cette nouvelle version. Ca pourrait à lui seul justifier que des projets emprisonnés dans Python 2.7 passent en Python 3! Sauf que … il existe un backport Python 2 !

      C'est pas forcément simple. Nous on est bloqués par Twisted qui est bloqué (entre autres) par une fonctionnalité supprimée de Python 3: http://bugs.python.org/issue3982 . Et le passage à asyncio n'est pas à l'ordre du jour, Twisted a quand même une base de code, outils et protocoles supportés (dont XMPP) qui n'est pas prête d'être rattrapée, le tout étant très testé et stable. Bon ça avance quand même, y'a une partie utilisable en Python 3: http://blog.futurefoundries.com/2014/03/twisted-on-python-3-now-pip-installable.html .

      D'un autre côté y'a d'autres projets comme Pyjamas qui ne passeront peut-être jamais à Python 3.

      Bref, sans les dépendances, pas facile de songer à passer à Python 3 dans l'immédiat.

    • [^] # Re: asyncio vous emmène vers Python 3

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

      asyncio, c'est vraiment la killer-feature de cette nouvelle version. Ca pourrait à lui seul justifier que des projets emprisonnés dans Python 2.7 passent en Python 3! Sauf que … il existe un backport Python 2 !

      Trollius n'est pas identique à Tulip. La syntaxe Tulip est plus simple et courante (yield from …/return …) que celle de Trollius (yield From(…)/raise Return(…)) :
      http://trollius.readthedocs.org/#differences-between-trollius-and-tulip

      Et puis, il manque tellement de choses à Python 2 …
      http://haypo-notes.readthedocs.org/python2.html

      Bien sûr, il est possible de programmer les bras attachés dans le dos en tapant sur les claviers avec les dents.

      • [^] # Re: asyncio vous emmène vers Python 3

        Posté par . Évalué à 7.

        Bien sûr, il est possible de programmer les bras attachés dans le dos en tapant sur les claviers avec les dents.

        Ce qui permet, soit dit en passant, d'écrire de l'excellent code Twisted.

        • [^] # Re: asyncio vous emmène vers Python 3

          Posté par (page perso) . Évalué à 2. Dernière modification le 19/03/14 à 15:42.

          Tu as (vous avez ?) quoi contre Twisted plus précisément ?

          • [^] # Re: asyncio vous emmène vers Python 3

            Posté par . Évalué à 3.

            Personnellement, j'ai quelques raisons de ne pas trop aimer Twisted :
            - développeurs opposés à Python 3
            - communauté de développement en général assez peu agréable
            - architecture un peu byzantine et difficile à comprendre (surtout si l'on veut contribuer des trucs)
            - tendance à réinventer la roue

            Après, c'est personnel et ça ne reflète pas forcément l'avis des autres core développeurs de Python.

            (quant à XMPP, je suis content de savoir que ça marche aujourd'hui, à l'époque où j'avais essayé - vers 2007 -, c'était largement en chantier et le développeur principal n'accueillait pas vraiment les propositions de contribution)

            • [^] # Re: asyncio vous emmène vers Python 3

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

              Oki, je comprends mieux

              • développeurs opposés à Python 3

              J'ai appris le dernier coup que tu avais tenté un fork python 3, et effectivement ce n'est ouvertement pas dans leur priorités. Maintenant de ce que j'ai compris, ils veulent faire une base de code unique python 2/python 3 et garder la compatibilité ascendante, ce qui vu leur base de code et le nombre de services en production (que j'estime grand sans avoir de chiffre) me parait compréhensible.

              Comme indiqué dans mon commentaire plus haut, il y a tout de même une partie de Twisted qui tourne sur Python 3, et pour le reste ils ont l'air bloqué par le bogue mentionné.

              Maintenant je suis ça d'assez loin pour le moment, Python 3 n'est pas dans nos priorités non plus, mais la question va se poser de plus en plus, et asyncio n'est pas prêt de rattraper le nombre de protocols supportés par Twisted de sitôt.

              • communauté de développement en général assez peu agréable

              Perso je n'ai jamais eu à m'en plaindre, mais j'ai assez peu de contacts avec au final

              • architecture un peu byzantine et difficile à comprendre (surtout si l'on veut contribuer des trucs)

              Ça c'est clair que c'est pas évident à comprendre. Maintenant à l'usage faut reconnaître que ça permet de faire les choses rapidement, j'ai pu lier un serveur IMAP à du XMPP en 1 soir ou 2.

              • tendance à réinventer la roue

              Il y a aussi beaucoup de choses qui étaient là avant (genre ils utilisent le CamelCase parce que la PEP08 a été faite après si je ne m'abuse). Après c'est vrai qu'il y a des choses qu'ils auraient pu réutiliser (logging, test ?), je suppose qu'il y a de bonnes raisons à tout ça.

              (quant à XMPP, je suis content de savoir que ça marche aujourd'hui, à l'époque où j'avais essayé - vers 2007 -, c'était largement en chantier et le développeur principal n'accueillait pas vraiment les propositions de contribution)

              En dehors de la base dans Twisted, le gros du XMPP est dans Wokkel, qui est une bibliothèque par dessus Twisted et dont le code devrait être mergé à Twisted à terme. C'est encore incomplet, mais y'a de grosses parties implémentées dedans (MUC par exemple), et c'est bien pratique.

              Bon en tout cas c'est un peu plus clair, mais même si tu n'aimes pas Twisted, moi c'est un choix que je ne regrette pas: c'est toujours activement développé, c'est très stable (j'ai eu très peu de bogues liés à Twisted/Wokkel jusqu'ici), et c'est puissant. Du coup je trouve ta pique plus haut un peu sévère.

              J'espère que Twisted pourra facilement échanger avec asyncio, mais de ce que j'ai compris, les dévs principaux de Twisted et Guido ont longuement discuté ensemble, et c'est justement un des buts affichés.

              Bon et sinon bravo pour le boulot général, j'espère ne pas rester éternellement bloqué à Python 2 (y'a aussi Pyjamas qui va poser problème), c'est alléchant tout ça :)

  • # Deux petites questions

    Posté par . Évalué à 3.

    J'ai deux petites questions naïves en attendant que les paquets de python 3.4 arrivent pour ma distribution.

    nouveau protocole 4 de sérialisation pour le module pickle (PEP 3154) : plus compact et permet de sérialiser des objets qui ne pouvaient pas être sérialisés avec Python 3.3

    Est-ce que ça veut dire qu'on pourra utiliser le module multiprocessing en appelant une fonction membre d'une classe par exemple ? Pour le moment si je fais un Pool().map(self.member_func, self.args) il me semble que j'ai une erreur à cause de pickle.

    le module multiprocessing a une nouvelle option pour éviter d'utiliser os.fork() sous UNIX (voir multiprocessing.set_start_method()) ;

    Si j'utilise forkserver, est-ce ques les données en mémoire sont copiées pour chaque processus ou bien est-ce qu'on bénéficie encore du copy-on-write comme avec fork() ?

    Sinon pour ma part je ne touche plus à python 2. J'ai encore le paquet installé à cause d'une paire de logiciels n'ayant pas encore migré mais c'est bien tout. Je ne saurais plus me passer de python 3. D'ailleurs, est-ce qu'il y a une date en discussion pour la mise à mort officielle de python 2.7 ?

    • [^] # Re: Deux petites questions

      Posté par . Évalué à 2.

      Si j'utilise forkserver, est-ce ques les données en mémoire sont copiées pour chaque processus ou bien est-ce qu'on bénéficie encore du copy-on-write comme avec fork() ?

      Tout l'intérêt est d'éviter d'hériter des données (et surtout des ressources systèmes : fichiers ouverts, sockets, verrous…) du processus principal, donc la question ne se pose pas : pour passer des données au fils, il faut les sérialiser.

      Techniquement, cela fonctionne en lançant un premier processus fils indépendant (le forkserver) qui forkera un fils à chaque demande du processus principal : ainsi chaque fils forké l'est rapidement (fork() est rapide) mais il est entièrement vierge de toute donnée héritée du processus principal (il hérité des données du forkserver, mais il est léger).

      • [^] # Re: Deux petites questions

        Posté par . Évalué à 4.

        Tout l'intérêt est d'éviter d'hériter des données (et surtout des ressources systèmes : fichiers ouverts, sockets, verrous…) du processus principal, donc la question ne se pose pas : pour passer des données au fils, il faut les sérialiser.

        Je n'utilise peut-être pas les bon mots, je ne suis pas spécialiste du domaine. Disons que je fais n calculs en parallèle sur un tableau numpy qui peut faire quelques dizaines de Go mais je ne modifie jamais ce tableau. Si je passe naïvement ce tableau ça massacre les performances dans les grandes largeurs, sans parler de l'occupation en mémoire. Donc je cherche à partager ce grand tableau entre les processus. Pour cela je mets les données dans un module tiers que j'importe et par la magie du copy-on-write ça marche bien et vite avec fork(). Le problème est que sur d'autres plateformes ou avec certaines bibliothèques numériques, style OpenBLAS, fork() mène à un deadlock. En théorie forkserver est une solution de ce que j'ai lu¹. Je me demande donc si la méthode de partager des données via un import va fonctionner aussi bien avec forkserver.

        ¹ https://github.com/obspy/obspy/wiki/Notes-on-Parallel-Processing-with-Python-and-ObsPy

        • [^] # Re: Deux petites questions

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

          Il existe différentes méthodes pour partager des données entre plusieurs processus, notamment la mémoire partagée. Dans le cas précis de numpy, je ne sais pas ce qui est le mieux.

          J'ai déjà écrit un programme qui partage de la mémoire avec mmap, ça se fait facilement.

        • [^] # Re: Deux petites questions

          Posté par . Évalué à 2.

          Je me demande donc si la méthode de partager des données via un import va fonctionner aussi bien avec forkserver.

          Non (de façon délibérée, comme je l'ai expliqué).

        • [^] # Re: Deux petites questions

          Posté par . Évalué à 6.

          Donc je cherche à partager ce grand tableau entre les processus. Pour cela je mets les
          données dans un module tiers que j'importe et par la magie du copy-on-write ça marche bien
          et vite avec fork().

          Atention quand même avec le COW : en effet, tu n'as pas à te tapper la sérialisation.
          Mais comme CPython utilise le comptage de référence, le simple accès en "lecture seule" de ce tableau (par exemple juste un itération) va provoquer une duplication des pages, d'où risque de OOM.

    • [^] # Re: Deux petites questions

      Posté par . Évalué à 2.

      D'ailleurs, est-ce qu'il y a une date en discussion pour la mise à mort officielle de python 2.7 ?

      Pas avant quelques années, je pense.

  • # asyncio et socketserver

    Posté par . Évalué à 1.

    Je profite de cette dépêche pour vous poser une petite question.
    Sur un jeu que je développe, j'utilise la class ThreadedTCPServer sur la partie serveur pour communiquer avec un client écrit en C++/Qt (ça marche correctement pour une connexion mais je n'ai pas encore testé la montée en charge).

    Ai-je un quelconque avantage à passer au module asyncio ?

    Merci

    Matt

    • [^] # Re: asyncio et socketserver

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

      Utiliser des threads est simple à programmer (si chaque requête n'utilise pas de ressource partagée), mais n'est pas performant pour gérer un grand nombre de requêtes concurrentes. Je m'attends à de meilleures performances avec un grand nombre de requêtes concurrentes (de beaucoup de clients différents).

  • # Cool !

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

    Plein de nouvelles bonnes choses à utiliser ! Bon, je ne pense pas en avoir tout de suite l'utilité (sauf les enum, et à ce propos c'est vrai que les symboles Ruby semblent assez sexy), mais le langage évolue bien, c'est agréable à voir.

    L'amélioration de SSL est un grand plus. Par contre, je regrette une chose, c'est les méthodes d'authentification HTTP qui se limitent à Basic et Digest.
    Je pensais notamment à Kerberos qui est quand même un peu utilisé, et que je trouve assez difficile à intégrer (notamment sur Windows).

    Au passage, le site officiel n'aurait-il pas beaucoup évolué ?

  • # Justin

    Posté par . Évalué à 8. Dernière modification le 21/03/14 à 15:24.

    Juste un commentaire pour dire que je trouve ce journal très intéressant et qui me conforte dans mon choix de rester sur du Python plutôt que céder à apprendre un autre Ruby/Dart/Go/PHP/Perl/…/etc [*] .

    Python connait ses dernier temps une progression que je trouve vraiment passionnante, essentiellement dans les domaines des : Maths (Canopy et Pandas n'y sont pas étrangers), Big DAta, et Data mining.

    [*] Ces langages ont leur propres intérêts, mais historiquement pour moi ceux que j'ai à mon actif me suffisent, et ce largement grâce à Python, d'où cette reflexion.

    • [^] # Re: Justin

      Posté par . Évalué à 6.

      J'adore Python, et dès que je peux le caser quelque part (donc, dans à peu près toutes les situations dans mon cas), je le fais.
      Mais apprendre d'autres langages, c'est franchement indispensable à mon gout. Ça permet d'apprendre de nouveaux paradigmes, d'aborder des problèmes sous un jour nouveau… et d'apprécier d'autant plus python.
      Et parfois, c'est sympa de connaitre un langage un poil plus bas niveau abstraction pour monter en perf (ou pour une partie "critique", ayant fortement besoin de garde-fou niveau prog'). Typiquement du C qui s'interface très bien dans un programme python. Et ainsi, on tape véritablement dans la niche de Python : le script. Un langage qui joue le rôle de chef d'orchestre.

      Après, si tu as le temps, je conseille de prendre un langage fonctionnel, type haskell ou ocaml (faudrait d'ailleurs que je prenne le temps de le regarder plus attentivement, celui-ci). C'est fou comme c'est formateur, et comme on devient un meilleur développeur. Sans forcément devenir un killer dans ces technos, juste les aborder est agréable.

      • [^] # Re: Justin

        Posté par . Évalué à 2.

        Intéressant. Autant je ne suis pas tout à fait ok pour ma liste est trop longue pour dire que je les maîtrise réellement tous; Autant un langage avec un logique d'approche comme ceux que tu cite présente un intérêt pour régler autrement des problèmes que les langages "courants" ne résoudront pas. Et d'ailleurs fan d'IA je me suis penché sérieusement sur LISP dans ce sens.
        Mais à la fin, j'ai abandonné car dans mon métier le C et C++ sont la plupart du temps imposés. Et d'ailleurs, si j'ai du aborder d'autres langages (Objective-C, C#, etc) c'est parce que on me le demandait pas par choix.
        Du coup il y à une forte différence entre ce que l'on peut faire, et ce que l'on doit faire.
        Python sort du lot pour moi car je le préfère largement à la syntaxe de bash, et vu sa versatilité j'ai même l'impression de m'amuser avec.

  • # Merci

    Posté par . Évalué à 1.

    Merci pour cette dépêche! Sinon une petite question pour les développeurs python : Comment voyez-vous la convergence entre python 2 et 3 ?

    Je pense commencer un nouveau projet sous python, et je vais probablement être obligé de partir en 2.7 , les modules que je souhaite utiliser (pyshark et pythonnet) n'étant pas dispo en python 3.

    Il y a t-il encore des points de langage bloquants encore la transition des modules vers python 3?

Suivre le flux des commentaires

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