Forum général.hors-sujets De la conception du langage Python

Posté par . Licence CC by-sa.
27
7
fév.
2018

Dans mon journal sur La recherche en langages de programmation au quotidien, Xavier Combelle demande un avis sur Python—sur les rapports entre Python et la théorie des langages de programmation, j'imagine. J'ai choisi de créer un sujet ici puisque c'est une discussion un peu "hors sujet".

Quel est ton avis sur mon langage préféré: python auquel je n'ai pas fait défaut depuis sa découverte il y a une dizaine d'année ?

Je voudrais discuter surtout des aspects qui concernent les aspects linguistiques eux-mêmes (le choix des fonctionnalités du langage, plutôt que des bibliothèques et programmes construits au-dessus), et aussi les aspects de gouvernance sur l'évolution de ce langage et les décisions qui sont prises aujourd'hui ou ont été prises dans le passé.

D'abord j'aimerais commencer par dire des choses qui me plaisent dans Python:

  • La gouvernance du projet est bien menée, avec un système de PEP (Python Extension Proposals) installé tôt et qui marche bien.

  • La syntaxe de Python est étonnamment sympa. C'est rare de voir un langage qui ressemble autant à ce qu'on écrirait naturellement comme pseudo-code. Je pense que c'est en grande partie lié à un vrai talent de son concepteur principal, Guido Van Rossum, pour trouver une jolie syntaxe. Ça aide pour enseigner Python aux débutants. C'est intéressant parce que la question de "quelle syntaxe est plus jolie/lisible qu'une autre" est une question sur laquelle on a très peu prise, scientifiquement : je ne connais pas de critère objectifs pour s'aider dans ces choix, et je pense que personne ne comprend bien les ingrédients de conception d'une bonne syntaxe.

  • Python a une très grosse communauté, vivante, qui apporte beaucoup de choses. Je suis par exemple un grand admirateur du projet SageMath (anciennement Sage), qui a réussi à fédérer une communauté entière autour d'un projet libre de taille, et du projet Jupyter (anciennement IPython) qui a eu un impact très positif sur les interfaces qu'on utilise pour programmer. Dans les logiciels libres qu'on utilise au jour le jour, beaucoup sont codés en Python, entièrement ou partiellement. (Je suis ravi d'y contribuer si j'en ai l'occasion.)

Maintenant quelques critiques :

  • Le créateur du langage, Guido Van Rossum, est globalement assez hostile aux idées venant de la programmation fonctionnelle (à part les compréhensions de listes, qui ont plu), et a eu dans le passé une attitude assez fermée vis-à-vis des universitaires du domaine. Ça ne l'intéressait pas de discuter pour comprendre des aspects de Python à améliorer, ce qui est toujours dommage. (Par exemple, il n'y a pas d'appels terminaux en Python, ce qui complique inutilement l'écriture de certains programmes récursifs, alors qu'on sait depuis les années 1990 2000 comment combiner appels terminaux et backtraces (A Tail-Recursive Machine with Stack Inspection, John Clements, Matthias Felleisen, 2004), qui est la raison invoquée pour leur absence). Maintenant la gouvernance de l'évolution du langage est plus distribuée, et Guido a peut-être un peu revu sa position, donc les choses se sont améliorées.

  • Il y a quelques erreurs de conception qui étaient présentes dès le départ dans le langage et qui viennent d'une ignorance de concepts basiques quand on étudie les langages de programmation. Par exemple, la portée lexicale (la portée des variables avec déclarations imbriquées) est mal conçue, et a nécessité l'ajout du mot-clé nonlocal (un exemple d'évolution du langage bien menée mais qui aboutit quand même à une solution moche pour un problème qui n'aurait pas dû être là au départ).

  • C'est un langage non typé statiquement qui est cependant utilisé pour de gros projets. Personnellement je suis convaincu que les types statiques jouent un rôle essentiel pour permettre la maintenance et le refactoring de code dès qu'on a un projet un peu gros, et je trouve que développer quelque chose comme Django en Python crée des logiciels très difficiles à gérer (même quand on fait un effort considérable sur les tests). Les systèmes de types statiques ne sont pas sans défauts non plus, et le fait d'explorer des idées dans un langage sans typage statique est très raisonnable, mais ça ne produit pas des langages que j'ai envie d'utiliser moi-même, et que je ne pas qu'ils soient adaptés pour de gros projets. (Mais souvent les gros projets commencent petit.) D'ailleurs les efforts actuels pour ajouter du typage après-coup à Python sont majoritairement motivés par ces problèmes de maintenance à grande échelle. Ils sont très difficiles et douloureux—bien plus difficile que si le langage avait été conçu avec du typage dès le départ. Il y a sans doute des gens avec un bagage théorique qui vont se pencher sur la question de proposer un typage de Python après-coup, mais je leur souhaite bien du courage.

Voilà, j'ai donné un avis sur Python, mentionnant seulement quelques aspects qui me viennent à l'idée directement. Je pense que c'est important de comprendre qu'aucun langage n'est parfait, et qu'une communauté peut développer des choses de valeurs tout à fait indépendamment des caractéristiques du langage lui-même. Ceci dit, moi j'évite d'écrire du Python sauf pour des petits scripts, et mes expériences de contribution à de plus gros projets dans ce langage (des sites en Django typiquement) m'ont confirmé dans l'impression que ça peut être assez pénible au quotidien de travailler dans un langage non typé sur un gros projet. (Mais ça pourrait être pire, PHP par exemple.)

  • # Merci

    Posté par . Évalué à 4.

    Salut,

    Merci de partager ta vision du langage !

    Python est un langage que j'aime beaucoup et que j'utilise quotidiennement, y compris pour des gros projets ;) Je ne peux qu'abonder dans ton sens (j'ai beau apprécier le langage, ça ne m'empêche pas d'être critique envers lui !). Heureusement, les outils et PEP "modernes" (je pense à PyCharm et la PEP 484) sont d'une aide bien utile dans les cas que tu évoques (maintenance, réusinage de code).
    Mais effectivement, ça a pour le moment plus l'apparence d'une rustine que d'une fonctionnalité intégrée dans le langage.

    • [^] # Re: Merci

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

      Je suis bien d'accord avec toi sur PyCharm. J'utilise beaucoup le TypeHinting, je n'hésite pas à rajouter s'il le faut des assert isinstance(x, y) ou un commentaire pour l'aider et je n'utilise que très exceptionnellement le typage dynamique (quand ça permet de vraiment simplifier le code). Au final, ça marche bien et j'ai vraiment très peu de bugs liés à des problèmes de type.

      C'est de façon générale quelque chose de très demandé et étudié, on peut espérer du progrès à ce niveau (c'est également nécessaire pour augmenter les perfs).

      • [^] # Re: Merci

        Posté par . Évalué à 10. Dernière modification le 07/02/18 à 22:01.

        C'est de façon générale quelque chose de très demandé et étudié, on peut espérer du progrès à ce niveau (c'est également nécessaire pour augmenter les perfs).

        Oui, ou alors on peut aussi utiliser dès le départ un langage typé et plus performant.

        (Il y a un côté ironique à voir plein de gens utiliser un langage pour faire quelque chose pour lequel il n'a pas été conçu au départ, se rendre compte que ça coince, et se mettre à tous dire en groupe : « on est tellement nombreux à avoir des ennuis, quelqu'un va bien finir par nous sortir du fossé ».)

        • [^] # Re: Merci

          Posté par . Évalué à 3.

          Je pense que c'est une histoire de compromis : même lorsque j'étais assez efficace en C/C++, ça me prenait énormément plus de temps d'implémenter une fonctionnalité/programme que sur du python (sans compter le temps passé initialement à mettre en place la compilation du programme, même en partant d'un patron déjà écrit, etc). Là, en partant de 0, je peux avoir mon environnement python installé sur une machine en moins de temps qu'il n'en faut pour télécharger gcc ;-) (j'exagère un peu mais je pense que ça reste néanmoins une bonne comparaison je trouve). De l'autre côté, je suis prêt à devoir faire preuve d'un tout petit plus de rigueur lorsque je code.
          Même sur un projet relativement récent où j'utilise les annotations, je n'en mets par partout et je ne me limite qu'aux cas les plus complexes ou ambigus (causés potentiellement par une mauvaise architecture du code en amont, ou des choix historiques).

        • [^] # Re: Merci

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

          Python permet de développer vite, très vite, et en tout cas personnellement, je ne me vois pas développer aussi vite avec un autre langage de programmation (que ce soit grâce au langage lui-même, aux outils, à la bibliothèque standard ou aux bibliothèques existantes de façon générale).
          Accessoirement, les morceaux qui ont réellement besoin de perf constituent rarement la majeure partie du code. Pour 95% du code (statistique complètement au jugé, évidemment), Python convient très largement.

          Dans certains cas, c'est tout bêtement beaucoup plus rentable pour mon employeur de payer un ou deux serveurs supplémentaires que de me payer du temps supplémentaire à optimiser ou refaire dans un autre langage les parties requises.
          Dans d'autres cas, c'est simplement un choix entre « un projet qui pourrait être plus rapide mais qui fonctionne » et « pas de projet du tout ». À nouveau, le choix est vite fait, même si on préférerait toujours avoir plus de perfs.

  • # Langage sympa, mais pas fait pour être maintenable

    Posté par . Évalué à 3. Dernière modification le 08/02/18 à 13:35.

    J'aime python, mais pour l'utiliser dans le cadre de vrais gros projets, c'est quand même bancal à mon goût.
    Voilà les raisons :

    Pas de constantes

    Ai-je vraiment besoin d'étayer ?

    Gestion des dépendances mal fichue

    Gérer les dépendances avec pip ou easy_install est considérée comme obsolète alors que ce sont les outils fournis d'office. Et pour cause, le méli-mélo de versions de libs est un cauchemar.

    Pas de typage dans les déclarations de méthode, même pas en commentaire

    Ça rend la doc des fonctions, classes et modules juste misérable. Si au moins on pouvait avoir un équivalent de PHPDoc, et qu'il soit accepté par la communauté comme un standard, ça aiderait.

    Self explicite dans les classes

    Je ne comprends toujours pas pourquoi ce mot clé est obligatoire dans les fonctions d'une classe. Et je ne comprend pas non plus qu'on doivent encore alourdir le code en disant qu'on veut accéder à self pour accéder à une propriété d'une classe. Ça rend quasi obligatoire les affectations vers des variables locales pour ne pas rendre le fonctionnel illisible. Alors je sais que c'est pas le seul langage de script où c'est le cas, mais ça n'est pas une raison pour pourrir son code.

    Les modules

    Je sais que ça commence à s'améliorer doucement avec python3 et des brouettes, mais franchement, ça reste moisi. Et tout ça alors que c'est un besoin primaire de programmation de pouvoir facilement diviser son code en plusieurs fichiers. Ça trouve le moyen d'être plus louche que PHP composer et ses PSR.

    Outillage pour les tests unitaires immature

    Heureusement que nose existe, parce que franchement sans cet outil, c'est l'âge obscur pour lancer les tests unitaires et gérer les imports du code testé dans les tests unitaires. Mais ça reste pas franchement folichon par rapport à ce qu'on trouve ailleurs.

    Malgré tout ça, j'aime ce language

    Malgré toutes ces critiques, ça reste un chouette langage pour de petits projets ou pour automatiser de l'administration système. J'ai deux projets en cours avec des scripts d'administrations système assez costauds et python est un bon outil pour faire ça. C'est une alternatives appréciable aux infâmes scripts bash/sh où la gestion des erreurs reste approximative, où c'est difficile de modulariser son code et où faire des tests unitaires reste encore aujourd'hui un défi.
    Par contre, si j'avais une vraie appli à faire, je ne ferai clairement pas ça en python, toujours pas.

    • [^] # Re: Langage sympa, mais pas fait pour être maintenable

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

      Pas de typage dans les déclarations de méthode, même pas en commentaire
      Ça rend la doc des fonctions, classes et modules juste misérable. Si au moins on pouvait avoir un équivalent de PHPDoc, et qu'il soit accepté par la communauté comme un standard, ça aiderait.

      Je ne comprends pas trop… Pour la doc, il y a sphinx qui est très clairement le standard de facto, et tu peux indiquer le type comme tu veux. Tu peux également utiliser le TypeHinting, qui est utilisé par les IDE dignes de ce nom.

      Les modules
      Je sais que ça commence à s'améliorer doucement avec python3 et des brouettes, mais franchement, ça reste moisi. Et tout ça alors que c'est un besoin primaire de programmation de pouvoir facilement diviser son code en plusieurs fichiers. Ça trouve le moyen d'être plus louche que PHP composer et ses PSR.

      Quel est le problème pour découper en modules ?

      • [^] # Re: Langage sympa, mais pas fait pour être maintenable

        Posté par . Évalué à 2. Dernière modification le 09/02/18 à 12:59.

        Au temps pour moi, j'étais pas au courant pour sphinx, mea culpa. Merci beaucoup pour l'info.

        Le souci avec les modules c'est déjà le init.py qui est un mécanisme franchement artisanal pour gérer la visibilité du contenu d'un module. Ça a le mérite d'être simple et clair, mais c'est pénible quand ton module commence à être complexe. Franchement, je préfèrerais mille fois avoir un mot clé public, private, protected ou n'importe quoi d'autre pour dire qu'une classe est accessible de l'extérieur. Au moins, ça donne une notion de visibilité du contenu du module, qui n'existe pas en ecmascript/javascript par exemple.
        J'ai remarqué qu'en plus, à cause de ça, pour pouvoir mocker des classes ou fonctions importées, on est obligé de dupliquer les imports.
        ex concret, avec du vrai code :

        from lib.tokens_downloader import TokensDownloader
        from lib.key_value_parser import KeyValueParser
        from lib.timestamp_generator import timestamp
        import lib.tokens_downloader
        import lib.key_value_parser
        import lib.timestamp_generator

        Tout ça pour pouvoir faire librement des @patch sur les dépendances. Ça reste moins moisi que les libs de mock en javascript, mais moins élégant que ce qu'on peut voir en groovy.

        L'autre point dont j'étais pas fan mais qui a été amélioré, c'est pour importer des modules qui sont dans d'autres dossiers d'une arbo.
        ex :

            ---- CWD
                |
                |-- lib
                |   |
                |   |--- a
                |   |    |-- toto.py -> class Hello
                |   |    |-- titi.py -> class Hella
                |   |
                |   |--- b
                |       |-- tata.py -> class Helluva
                |-- ext
                    |--- c
                    |    |-- yuyu.py -> class Bonjour
        

        La question est donc comment faire pour que toto.py référence de manière propre et modulaire les classes Hella, Helluva et Bonjour.
        Ce qui est considéré comme la bonne pratique dans plein de langages c'est les formes suivante :
        - pas besoin d'import pour Hella (ce qui ne marche pas en python) ou au pire une notation abrégée

        from titi import Hella
        
        • pour tous les autres, on considère souvent comme bonne pratique :
        from lib.b import Helluva 
        from ext.c import Bonjour
        

        Alors oui, c'est possible depuis peu en python3. Le souci, c'est que quand on regarde les docs officielles sur les modules,
        c'est un vrai défi de trouver quel est l'état de l'art, quelles sont les bonnes pratiques. Il m'a quand même fallu un paquet d'heures pour trouver comment importer proprement des modules. Je suis surtout tomber sur des réponses qui ressemblent à ça et qui donnent envie de se fracasser la tête contre les murs. Donc il n'y a plus trop de souci dans le langage, le problèmeest plutôt la qualité de la doc et des exemples de codes qui ne sont pas à jour. J'ai eu aussi l'impression qu'un pan de la communauté python n'est pas encore consciente de toutes ces nouveautés merveilleuses. Y aurait-il un manque de pub et de marketing sur les nouvelles versions du langage ?

        Pour finir, je pensais aussi critiquer le concept du PYTHONPATH, mais au final je n'ai aucun bon argument et c'est comme dans tous les autres langages du monde. Je n'ai donc aucune bonne raison de critiquer ça vu qu'il est difficile de proposer mieux.

  • # portée lexicale ?

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

    Je ne comprends pas bien ta critique de la portée lexicale comme étant un problème. A ma connaissance, les cas où il est nécessaire d'utiliser nonlocal est très rare dans mon expérience. en lecture de variable, il me semble que python a la portée attendue. Par exemple

    def f():
            x=5
            def g():
                    print(x)
            g()
    f()
    

    x a la portée lexicale que tu attends.

    l'utilisation de nonlocal n'est utile qu'en cas d'écriture dans une variable.

    • [^] # Re: portée lexicale ?

      Posté par . Évalué à 9.

      Pour moi le fait que la lecture d'une variable et son écriture se comportent différemment du point de vue de la portée n'a pas de sens (à part "c'est une erreur qui date d'il y a longtemps et on ne pouvait pas la corriger sans risquer de casser du code"), c'est un défaut du langage. Un débutant n'a pas de raison de comprendre pourquoi ça marche dans un cas et pas dans l'autre, et n'a aucune chance de deviner tout seul qu'il faut utiliser nonlocal—en fait personne ne connaît cette fonctionnalité ou presque. C'est un cas typique d'erreur de conception.

      Imagine que tu as écris:

      def f():
          x = 1
          print(x)

      maintenant pour une raison ou une autre, tu veux mettre la dernière ligne de code dans une fonction auxiliaire (et l'appeler pour conserver le même comportement):

      def f():
          x = 1
          def g():
              print(x)
          g()

      Ça marche très bien, ça fait la même chose. Mais pendant ce temps ton collègue a fait un commit dans son coin, et il a rajouté deux lignes à la fonction de départ:

      def f():
          x = 1
          print(x)
          x = 2
          print(x)

      Pas de soucis, tu règles le conflit de merge en rajoutant ces lignes dans ta fonction:

      def f():
          x = 1
          def g():
              print(x)
              x = 2
              print x
          g()

      Et là tu as une erreur UnboundLocalError! Incompréhensible.

      • [^] # Re: portée lexicale ?

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

        Je suis d'accord avec toi sur ce problème, et c'est dommage qu'ils n'aient pas profité de Python 3 pour changer également ça.
        Enfin, ils ont déjà corrigé LE plus gros problème de Python 2 à mes yeux, qui était le mélange unicode/str.

        Peut-être pour Python 4 ? :)

      • [^] # Re: portée lexicale ?

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

        C'est vrai que c'est incompréhensible. Après, faut avouer que c'est, comme tous les trucs surprenants, une super occasion d'aborder le fonctionnement de la visibilité en Python.

        Je trouve que c'est important de savoir assez vite la façon dont Python «résout» les variables et attributs (mro…), fais-je erreur ? D'autant qu'on peut enchaîner assez vite sur la surcharge de ce comportement.

        • [^] # Re: portée lexicale ?

          Posté par . Évalué à 2.

          Conclysion: Que de temps perdu sur un truc ma fichu! Si ça marchait comme attendu, tu n'aurais pas perdu de temps sur ce détail inintéressant au possible.

Suivre le flux des commentaires

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