Les changements de Python 2 à 3 rendent la refonte du code inévitable
La perspective de devoir se plonger dans un vieux code pour le faire fonctionner avec une nouvelle version de langage est l'une des choses que les développeurs essaient d'éviter à tout prix. Il est difficile de comprendre un vieux code ; des changements inattendus peuvent introduire de nouveaux bogues, les performances risquent d'en pâtir, et c'est un effort considérable pour peu de bénéfices. Après tout, vous n'ajoutez rien de nouveau, vous vous contentez de faire fonctionner le code comme avant. Ce billet couvrira quelques exemples de changements apportés par Python 2 et 3 qui rendent cette refonte du code inévitable.
Votre application Python 2 fonctionne comme prévu. Elle fonctionne parfaitement depuis quelques années, l'équipe de développement a résolu tous les problèmes et tout le monde est satisfait de ses performances. Elle fait le travail et s'efface dès qu'elle n'est plus nécessaire.
Mais, tout à coup, une nouvelle vulnérabilité est publiée, ciblant Python 2. Les correctifs de sécurité ne sont plus disponibles car la version 2 n'est plus officiellement supportée, de sorte que votre fantastique application, sans qu'il y ait eu faute de sa part, est maintenant vulnérable elle aussi et est devenue une responsabilité en matière de sécurité pour l'organisation. En tant que responsable informatique diligent, vous demandez à votre équipe de développement de donner la priorité au remaniement du code pour qu'il fonctionne avec une version sécurisée de Python 3.
Votre équipe avait d'autres projets en cours, et tout cela est maintenant mis en attente. C'est une décision coûteuse, mais il faut le faire, n'est-ce pas ? Il faut quelques semaines pour rassembler tous les détails concernant les changements de code nécessaires et la manière dont ils affectent d'autres sections du code, inattendues ou dont on ne se souvient plus. Une grande partie de la logique de base doit être réécrite, car certaines fonctionnalités ont été dépréciées depuis Python 2, et leur remplacement par Python 3 n'est pas automatique, de sorte que de nouveaux tests unitaires doivent également être créés.
Quelques semaines plus tard, les développeurs s'efforcent de comprendre un code mal documenté, écrit par un ancien collègue qui ne fait plus partie de l'organisation. Il semble que certaines sections du code "fonctionnent tout simplement", mais personne ne comprend plus pourquoi. Oh, et quelques dépendances ne supportent pas Python 3 et ne le feront probablement pas de sitôt - les projets semblent ne plus être supportés.
Après des mois de travail acharné, l'équipe de développement revient avec une nouvelle version de l'application. Elle ressemble légèrement à l'original ; certains choix d'interface utilisateur rendent difficile l'utilisation des connaissances accumulées, de sorte qu'une nouvelle formation des opérateurs est nécessaire.
Les performances semblent être affectées à chaque fois qu'une modification est apportée à la base de données. Personne ne sait exactement pourquoi, mais l'une des dépendances qui a dû être écrite à partir de zéro a permis de mieux gérer ce problème. Et tous les projets initiaux que l'équipe avait en main sont maintenant en retard et dépassent le budget.
L'équipe est revenue avec certains résultats à conserver comme connaissances utiles pour les futurs efforts de remaniement :
Division :
Python 3 : 5/2 == 2,5
Python 2 : 5/2 == 2 (doubler "/" en "//" renvoie à l'ancien comportement)
La division d'entiers renvoie désormais un float et non plus un int.
Imprimer :
Python 3 : print("")
Python 2 : print ""
Changements dans le dictionnaire :
Python 3 : méthodes dict keys(), items(), values() return views
Python 2 : ces méthodes renvoient des listes. Les méthodes iterkeys(), iteritems et itervalues() ne sont plus supportées.
Tri :
Python 3 : cmp() ne devrait plus être utilisé.
Texte et binaire :
Les données textuelles et binaires sont désormais des concepts différents et ne doivent plus être stockées dans des chaînes de caractères. Certaines opérations sur les chaînes de caractères ne fonctionnent plus sur des données qui fonctionnaient auparavant parce qu'elles contiennent des caractères qui ne sont plus autorisés dans les chaînes de caractères.
Tuples :
Les paramètres Tuple ne peuvent plus être décompressés comme auparavant.
Plusieurs mots-clés ont été supprimés :
“<>” is now “!=”.
Les littéraux entiers ne fonctionnent plus avec un l ou un L fermant.
Les chaînes littérales ne fonctionnent plus avec un u ou un U fermant.
L'importation de tout ce qui provient d'un module ne fonctionne désormais qu'au niveau du module, et non à l'intérieur d'une fonction.
Et beaucoup, beaucoup d'autres changements (la liste complète peut être consultée ici : https://docs.python.org/3/whatsnew/3.0.htmlqui a servi de source pour cet article).
À la fin du processus, l'application fonctionne moins bien qu'avant ; aucun avantage réel n'a été retiré du passage à un nouveau niveau de langage - seules des constructions remplaçant d'anciennes fonctionnalités ont été utilisées, et aucune nouvelle fonctionnalité avancée, car l'objectif était simplement de permettre à l'application de fonctionner à nouveau. Il s'agit d'une tâche coûteuse qui a affecté de nombreuses autres activités de l'organisation et provoqué des perturbations à tous les niveaux.
Qu'aurait-on pu faire à la place ?
Une meilleure alternative existe sous la forme de l'Extended Lifecycle Support for Python (support de cycle de vie étendu pour Python). Le problème aurait pu être résolu simplement en déployant le service, qui fournit des correctifs de sécurité opportuns sans introduire de changements au niveau du langage. Le même code aurait continué à fonctionner tel quel, la faille de sécurité aurait été corrigée et toutes les autres perturbations auraient pu être évitées.
