1
votes

Ai-je encore besoin de __future__ aujourd'hui?

Je ne suis pas très familier avec les cas d'utilisation du module __future__ de Python, mais je l'ai vu dans les codes de démonstration sur certains articles en ligne. Après avoir lu, je suppose que cela a quelque chose à voir avec la pérennité des codes existants? J'avoue que je ne comprends pas entièrement ce que je lis. Selon la documentation officielle, ses fonctions sont:

  • Pour éviter de confondre les outils existants qui analysent les instructions d'importation et s'attendent à trouver les modules qu'ils importent.
  • Pour garantir que les futures instructions s'exécutent sous les versions antérieures à 2.1, au moins génèrent des exceptions d'exécution (l'importation de future échouera, car il n'y avait pas de module de ce nom avant la version 2.1).
  • Documenter quand des modifications incompatibles ont été introduites et quand elles seront - ou ont été - rendues obligatoires. Il s'agit d'une forme de documentation exécutable et peut être inspectée par programme via l'importation future et l'examen de son contenu.

Que signifie le point 1? Cela dit-il que si un interpréteur lit une instruction d'importation et ne trouve pas le module qu'il importe, avoir import __future__ l'empêchera de import __future__ une erreur?

Avec Python 2.7 officiellement fin de vie le 1er janvier 2020, si je n'ai pas l'intention de prendre en charge les environnements Python 2 dans mon code Python 3, alors je suppose que le point 2 ne me concerne pas.

Le point 3 est pour ... le débogage, je suppose? Est-ce ce qu'il essaie de dire?

J'ai remarqué que tous les articles que j'ai lus jusqu'à présent datent d'au moins une demi-décennie. Tous les exemples se concentrent sur les codes Python 3 gérant la rétrocompatibilité Python 2, en particulier print et // . Mais comme je l'ai dit, je n'ai pas l'intention de prendre en charge Python 2.

À quoi sert __future__ en Python et comment / quand l'utiliser, et comment cela fonctionne

Alors, quand dois-je utiliser import __future dans le développement Python 3 si aucune rétrocompatibilité Python 2 n'est prévue? En ai-je même plus besoin dans un tel cas?


17 commentaires

Avez-vous vérifié la documentation ?


Si vous commencez avec une version Python moderne, aujourd'hui, vous n'aurez probablement besoin que des annotations avenir. Cela n'empêche pas Python d'introduire de nouveaux futurs dans le… futur.


Il peut être utilisé pour utiliser des fonctionnalités qui apparaîtront dans les versions plus récentes tout en ayant une version plus ancienne de Python.


@ThierryLathuille Oui, je l'ai fait, et d'après ce que je comprends, si je ne me soucie pas de supporter Python 2, alors je n'en aurai pas besoin, non? Ou y a-t-il encore d'autres utilisations?


@rcvaram Êtes-vous en train de dire que si j'ai, par exemple, un interpréteur Python 3.3 installé et qu'il lit import __future__ dans le script, il pourra utiliser les f-strings Python 3.6 sans avoir besoin d'installer Python 3.6?


@deceze Comment __future__ pour l'interpréteur actuel sait-il ce qu'il y a dans le futur? En théorie, si Python 3.12 introduit des fonctionnalités pour l'informatique quantique et qu'un interpréteur Python 3.3 lit le code écrit par un développeur Python 3.12 contenant __future__ , que se passe-t-il?


__future__ est une chose de compatibilité. Lorsque les développeurs Python décident de changer un comportement existant, ils ne peuvent pas nécessairement le faire tout de suite si cela briserait le code existant. Ils prévoient donc de changer ce comportement dans une future version de Python, et vous pouvez déjà opter pour ce changement aujourd'hui via __future__ . Ainsi, votre code continuera à se comporter de la même manière lorsque ce changement se produira réellement. Cela donne aux développeurs suffisamment de temps pour mettre à jour leur code entre l'annonce du changement et la mise en œuvre du changement, ce qui peut parfois prendre des années.


@deceze Donc, à titre d'exemple, si j'utilise import __future__ en Python 3.5, cela me permet d'utiliser des f-strings introduites dans Python 3.6 sans avoir besoin d'installer ce dernier?


Non, ce n'est pas arbitraire. f-strings où une fonctionnalité complètement nouvelle sans problèmes de compatibilité descendante. En 3.5 ils n'existaient pas, en 3.6 ils existent. Les rétroporter vers des versions antérieures n'a pas de sens. L'exemple actuel est que le comportement des annotations est prévu de changer dans 3.10. C'est prévu à l'avance. Vous pouvez mettre à jour votre code aujourd'hui et utiliser les __future__.annotations Pour déjà opter pour le nouveau comportement à l'avance et prouver votre code à l'avenir. Ces __future__.annotations été introduites dans la version 3.7 de Python en tant que nouvelle fonctionnalité.


@deceze Donc, ce que vous dites, c'est que les annotations sont officieusement disponibles depuis Python 3.7 via import __future__.annotations et qu'elles seront officiellement disponibles depuis 3.10 via import annotations est-ce ainsi que ça se passe?


Non! Le comportement de la façon dont les annotations de travail (une fonction de syntaxe, par exemple foo: bar = 'baz' ) changera subtilement à 3.10. Si vous écrivez du code aujourd'hui où ce changement est significatif, vous pouvez opter pour le nouveau comportement aujourd'hui en important le futur. Importer le futur après 3.10 ne fait simplement rien et votre code continue à se comporter avec le nouveau comportement par défaut. Chaque développeur dont le code pourrait être interrompu en raison de ce changement a jusqu'à la 3.10 pour mettre à jour son code afin qu'il fonctionne avec le nouveau comportement.


@deceze Ce que je veux dire, c'est: import __future__.annotations en Python 3.7 me permettront d'utiliser la version Python 3.10 import annotations ? Et si __future__ est destiné à un développeur pour accepter les modifications, que se passe-t-il si un utilisateur avec Python 3.5 exécute ce code 3.7 qui contient import __future__.annotations ?


Cela ne fonctionnera pas car cet avenir n'existe pas dans la version 3.5.


@deceze Donc, un utilisateur est toujours limité à exiger Python 3.7 et supérieur pour exécuter les scripts, mais un développeur peut utiliser __future__.annotations pour exécuter les fonctionnalités de Python 3.10 sans réellement mettre à jour son environnement de développement vers Python 3.10?


Il ne s'agit pas de «mise à niveau». 3.10 n'existe pas encore, vous ne pouvez pas «mettre à jour» si vous le souhaitez. Il s'agit de ceci: vous écrivez aujourd'hui du code qui attend un comportement A. Vous faites fonctionner ce code pendant de nombreuses années, sur différents ordinateurs, sur des versions de Python plus récentes et plus récentes au fil du temps. Finalement, ce comportement est changé en comportement B dans une version Python et votre code se rompt. Pour éviter cela, les développeurs Python annoncent ces changements bien à l'avance et vous donnent un moyen de préparer votre code pour ce changement en optant tôt pour le comportement B.


De cette façon, vous avez un code qui fonctionne de 3.7 à 3.10+. Sinon, vous devrez produire deux versions différentes de votre code, une qui fonctionne sur 3.9- et une pour 3.10+.


@deceze Donc, si j'utilise import __future__.annotations lors du développement en Python 3.7, j'utiliserai la version 3.10 des annotations , et tout utilisateur avec Python 3.7 et supérieur installé pourra exécuter ce code correctement? Ou dois-je toujours mettre à niveau mon environnement de développement vers Python 3.10 et changer mon code d' import __future__.annotations__ pour import annotations afin que les utilisateurs avec 3.10 et plus puissent utiliser le script?


3 Réponses :


0
votes

Modifications du logiciel

C'est le problème fondamental dont tout cela traite. Le logiciel est en constante évolution. C'est doux après tout. Lorsque vous écrivez du code aujourd'hui et que vous l'exécutez, il se comporte d'une certaine manière. La semaine prochaine, vous déciderez que vous n'aimez pas ce qu'il fait et qu'il a besoin de quelques changements. Vous le modifiez et l'exécutez, et il se comporte différemment maintenant. Si vous suiviez un flux de travail de publication approprié, vous étiqueteriez votre logiciel avec des numéros de version et vous auriez maintenant produit deux versions différentes de votre logiciel.

Python n'est également qu'un logiciel, écrit par des personnes qui ne sont que des programmeurs. L'impact des changements dans le langage Python est évidemment un peu différent de celui de changer votre petite application que vous n'exécutez que vous-même. Si les développeurs Python décidaient demain que la prochaine version de Python nécessitait des points-virgules à la fin de chaque ligne pour ressembler davantage à d'autres langages, il faudrait des milliers et des milliers de développeurs de logiciels pour réécrire des millions et des millions de lignes de code pour le rendre compatible avec cette nouvelle version de Python. De toute évidence, ce serait insensé, donc les développeurs Python n'apporteront pas de changements aussi radicaux et assureront une rétrocompatibilité raisonnable avec le code existant.

Pourquoi des changements?

Alors, pourquoi changer quoi que ce soit? Pourquoi ne pouvons-nous pas simplement conserver la version actuelle de Python et la version actuelle de notre code et continuer à l'exécuter pour toujours tel quel? Eh bien, vous pourriez . C'est une stratégie parfaitement fine, dans certaines limites. Il existe trois catégories principales de modifications, qui se reflètent dans le schéma de gestion des versions de Python:

  • Changements de version de XYZ: lorsque la version 3.7.1 de Python est mise à jour vers 3.7.2, c'est parce que des bogues ont été trouvés dans 3.7.1 qui nécessitaient une correction. Il s'agit souvent de correctifs de sécurité. Le code existant doit continuer à fonctionner tel quel, à moins qu'il n'ait été directement affecté par le bogue en question. Vous devez toujours garder votre version Python en production à jour avec la dernière version du correctif, pour vous assurer que vous ne tombez pas à cause des vulnérabilités de sécurité.
  • Changements de version XY: lorsque Python publie une nouvelle version comme 3.8, c'est pour introduire de nouvelles fonctionnalités. Vous voudrez passer à cette version si vous souhaitez utiliser ces nouvelles fonctionnalités, car elles facilitent votre travail ou votre code plus agréable. Ces versions introduisent aussi parfois des changements de rupture , par exemple la suppression de fonctions obsolètes ou la modification de fonctions existantes de manière mineure. Pendant que vous mettez à jour consciemment vers cette nouvelle version en raison de nouvelles fonctionnalités, vous pouvez également vérifier si vous pourriez être affecté par des modifications importantes et corriger votre code en conséquence.
  • Changements de version X. Cela s'apparente généralement à une langue entièrement nouvelle, ce qui se produit très rarement. Python 3 a introduit de nombreuses modifications par rapport à Python 2, ce qui a rendu beaucoup de code tout simplement incompatible et a nécessité une réécriture parfois importante du code existant. En guise d'avantage, Python 3 contenait des améliorations significatives qui rendaient le changement intéressant.

Il y a des pages entières dans la documentation consacrées à ces changements, et vous devriez les parcourir de temps en temps, et surtout avant toute mise à jour majeure: https://docs.python.org/3/whatsnew/index.html

Il existe donc diverses incitations à suivre les changements dans le langage Python, bien qu'ils soient tous facultatifs. Si vous voulez rester sur une version spécifique de Python pour toujours et à jamais, vous le pouvez. Jusqu'à ce que vous ayez besoin de remplacer le matériel sur lequel il fonctionne et que vous constatiez que cette version n'est pas compatible avec votre nouveau matériel de remplacement…

Compatibilité

Il existe différents problèmes de compatibilité. Lorsque de nouvelles fonctionnalités sont introduites, cela introduit une version minimale requise pour tout code utilisant cette fonctionnalité. Par exemple, ce code:

from __future__ import annotations

Cela utilise des chaînes f, une fonctionnalité syntaxique introduite dans Python 3.6. Si vous écrivez ce code, vous avez besoin d'au moins Python 3.6 pour l'exécuter. Python 3.5 refuse d'exécuter ce code, car il n'a aucune idée de ce que sont les f-strings. Cependant, ce type de changement n'a aucun problème de compatibilité ascendante . La syntaxe f'' est simplement une erreur de syntaxe dans les anciennes versions de Python et ne fonctionne tout simplement pas.

Les changements qui fonctionnent sur les anciennes versions de Python, mais se comportent différemment , sont plus préoccupants. Le problème actuel concerne les annotations:

foo: 'bar' = 'baz'

Le comportement de ceci changera subtilement dans Python 3.10. C'est un changement qui a été décidé et qui s'en vient. À partir de Python 3.10, le code ci-dessus se comportera comme:

foo: bar = 'baz'

En d'autres termes, les annotations seront évaluées comme des chaînes et non comme des objets. Pour la plupart des développeurs, cela ne fera que peu de différence et résoudra en fait certains problèmes avec des annotations tels qu'ils fonctionnent aujourd'hui. D'où ce changement. Cependant, en fonction de ce que vous faites avec les annotations, cette modification peut également casser votre code.

Futures

Et ainsi nous arrivons enfin à l'avenir: vous pouvez opter pour le nouveau comportement des annotations aujourd'hui si vous utilisez au moins Python 3.7 en important le futur approprié:

print(f'foo {bar} baz')

Si vous faites cela dans votre code, votre code évaluera déjà les annotations comme des chaînes aujourd'hui. Ce comportement deviendra par défaut dans Python 3.10. En d'autres termes, ce changement a été implémenté dans Python 3.7, mais est facultatif et opt-in. Il deviendra obligatoire en 3.10. À ce stade, à from __future__ import annotations ne feront tout simplement rien; que vous le spécifiez ou non, votre code se comportera dans un sens et dans un seul.

Cela donne aux développeurs trois versions principales, ou environ trois ans, pour mettre à jour leur code s'ils en ont besoin. De cette façon, personne ne sera surpris par la rupture de leur code si et quand ils essaient d'exécuter leur code existant sur Python 3.10 un jour. (À moins qu'ils n'aient vécu sous un rocher ces dernières années, et qu'il y aura des gens comme ça, malheureusement. Mais l'impact sera grandement minimisé.)

C'est donc à cela que sert l'avenir. Ils implémentent des changements de rupture, mais cachent ces changements derrière une import opt-in explicite, afin de permettre une fenêtre glissante dans laquelle les développeurs peuvent mettre à jour leur code afin de ne pas obliger des milliers de développeurs à réécrire leur code en panique lorsqu'ils ' sont soudainement confrontés à des codes de rupture en production car leur version de production Python a été mise à niveau pour une raison ou une autre.

Et ce n'est pas seulement une relation directe entre les développeurs Python et les codeurs comme vous; vous dépendez souvent de bibliothèques tierces, et celles-ci devront également être mises à jour. Chaque modification apportée au langage Python a un lent effet de retombée de Python vers les développeurs de bibliothèques, les mainteneurs de référentiel et les codeurs comme vous. Cela demande simplement du temps et les contrats à terme achètent ce genre de temps.

Il y a eu une tonne de ces types de changements au cours des années où Python était en train de passer de Python 2 à Python 3, et bon nombre des changements de rupture introduits dans Python 3 pourraient lentement être transposés avec l'utilisation de futurs. Au moment de la rédaction de cet article, il n'y a que le changement d'annotations susmentionné qui est actuellement une préoccupation active. Mais cela n'empêche pas Python d'introduire d'autres changements nouveaux et révolutionnaires qui seront déployés dans le futur dans ... le futur.


Les points que vous citez dans la documentation que vous ne comprenez pas ne sont pas très importants et ne sont que des détails de mise en œuvre interne. En un mot, même si les contrats à terme optent pour l'utilisation from ... import ... déclarations from ... import ... , ce ne sont pas de véritables importations de modules. Ce sont des indicateurs de compilateur qui semblent juste importer un module réel. (Une importation de module réelle n'aurait pas le genre de pouvoir pour apporter les changements que ces futurs modifient réellement.) Ce que vous citez dans la documentation est simplement d'expliquer que, comme il ne s'agit pas d'importations réelles, certains outils peuvent devenir confus s'ils essayez de les traiter comme des importations de modules réelles. Dans ce seul but, il existe un module « __future__ valide, et cette documentation que vous citez est à peu près cela et explique pourquoi il existe même quand il n'a aucun effet réel.


11 commentaires

"Le logiciel est en constante évolution. Il est doux après tout. " La stabilité est une bonne qualité, en particulier dans les langages et les outils de programmation. Le "soft" dans le logiciel ne concerne pas son taux de changement (qui serait idéalement nul) mais la facilité avec laquelle un tel changement est effectué.


Bien sûr, ça ne change pas tout seul , ce serait… inquiétant. Mais il est malléable et évolue petit à petit avec le temps. Le code qui est écrit une fois et jamais changé n'est souvent tout simplement pas intéressant pour personne.


Être malléable n'implique pas de changer dans le temps. En fait, un code qui ne change jamais est idéal (et s'il n'a été écrit qu'une seule fois, c'est encore mieux). Je ne vois pas en quoi cela le rend inintéressant (ni pourquoi être intéressant ou pas compte, pour être honnête).


Je parle du point de vue de la gestion de projet logiciel. Un projet comme Python est intéressant pour beaucoup de gens, et beaucoup de gens y apportent des améliorations, donc il change avec le temps. Oui, dans certains domaines, un logiciel stable en écriture unique est idéal et dans une certaine mesure requis, mais ce n'est certainement pas l'écosystème Python.


Étant donné le temps qu'il me faut pour faire défiler la réponse sur mon téléphone, je suppose que personne ne la lira entièrement :) Je ne peux qu'imaginer l'effort qui a motivé sa rédaction.


@deceze Je parle aussi du point de vue de la gestion de projet logiciel. Python n'est pas intéressant car il change avec le temps, mais parce qu'il résout un problème. C'est la stabilité, et non le changement, ce qui permet aux projets Python d'exister pour commencer. C'est aussi pourquoi les transitions comme Python 2 -> 3 sont douloureuses et prennent trop de temps.


@deceze Prétendre que l'écosystème Python a une sorte de qualité positive "toujours changeante" est trompeur et nuit à l'image de Python. Le bien-fondé de tous ses changements est comparé à la complexité et à la responsabilité qu’ils introduisent, pour une bonne raison.


@Acorn Le thème des futurs concerne précisément la gestion des changements. Si Python ne changeait pas, il n'aurait pas besoin d'avenir. Donc, présenter cette réponse avec une explication du changement de logiciel est logique, non? Je ne sais pas pourquoi vous vous opposez à la réalité de tels changements et transitions.


@deceze Ouais, __future__ est utilisé pour faciliter le travail autour des changements de rupture, c'est-à-dire pour augmenter la stabilité. Je n'ai rien discuté sur les changements en cours, mais sur les raisons derrière ces changements et sur l'idée que Python embrasse en quelque sorte le changement pour le plaisir du changement.


@deceze Concernant votre question, je pense qu'il est toujours utile de donner un peu de contexte sur n'importe quelle réponse, mais celle-ci aborde plusieurs sujets tangentiels en longueur qui ne sont pas vraiment nécessaires (et déclenchent des discussions hors sujet comme celle que nous venons d'avoir :) Au fait, d'où vient le mot «avenir»? Le module s'appelle futur car il s'agit d'importer des changements de rupture depuis le futur, mais je pense que c'est la première fois que je vois quelqu'un appeler les fonctionnalités elles-mêmes "futures".


@Acorn Après mes longs allers-retours avec l'OP dans les commentaires de question, j'ai été inspiré pour écrire cette réponse, car je pense que cela aiderait OP à comprendre le sujet. Peut-être que ce ne sera pas le cas, pas de chance. Quoi que vous y lisiez, je n'en ai aucune idée.



1
votes

Utilisez __future__ lorsque vous souhaitez être proactif dans la modernisation de votre code.

Dans de nombreux cas, vous vous surprendrez à l'utiliser lorsque vous jugerez qu'une nouvelle fonctionnalité en vaut la peine pour votre projet, mais vous devez toujours prendre en charge les anciennes versions de Python.

Cependant, vous pouvez également l'utiliser pour réduire votre dette technologique en cas de modifications futures et éviter les fractionnements de version dans votre projet.


0 commentaires

0
votes

Quel est l'intérêt de __future__ ?

__future__ permet d'introduire un nouveau comportement dans le langage qui serait rétrocompatible . Par exemple, dans Python 2.2 - 2.7, vous pouvez faire:

+----------------|---------------|----------------+
|    feature     | __future__ in | implemented in |
|----------------|---------------|----------------|
|----------------|---------------|----------------|
| generator_stop |      3.5      |      3.7       |
|----------------|---------------|----------------|
|  annotations   |      3.7      |      3.10      |
+----------------|---------------+----------------+

__future__ signifie "nous avons ajouté cette fonctionnalité dans le langage, mais nous ne pouvons pas en faire la valeur par défaut car cela briserait un autre code".

Pourquoi __future__ a-t-il été introduit à l'origine?

Supposons que vous ayez un projet Python 2 et que vous souhaitiez le faire passer à Python 3. Plutôt que de le convertir en un «big bang» et en espérant qu'il se comporte toujours de la même manière sous Python 3, les développeurs peuvent mettre à niveau leur projet pièce par pièce , en important d'abord la division par exemple et en testant les régressions, puis en important print_function et ainsi de suite.

À quoi sert __future__ dans Python 3?

Une version "Python 4" n'est pas à l'horizon . Mais deux fonctionnalités ont déjà été ajoutées à Python 3 de cette façon:

>>> 3/2
1
>>> from __future__ import division
>>> 3/2
1.5

Ces deux changements étaient incompatibles avec les versions antérieures . Cela signifie que les responsables du langage ont apporté un grand changement au fonctionnement des générateurs qui était prêt pour la version 3.5. Cependant, ils l'ont "caché" dans le module __future__ , car ils craignaient qu'un tas de paquets ne se brise lors de la sortie de 3.5 s'ils le sortaient directement.

Il y a toujours des changements plus petits et incompatibles avec Python, par exemple l'introduction des mots-clés async et await dans la version 3.7, ce qui rend le code qui les utilisait comme noms de variables ( async = 1 ) cassé. C'est vraiment un appel au jugement pour savoir s'il faut introduire une fonctionnalité directement ou en tant que __future__ , en fonction de l'effort d'une migration.

Ainsi, le mettre dans un __future__ avec un DeprecationWarning permet une période de transition pour les mainteneurs, ce qui permet d' activer la fonctionnalité plus tôt.


0 commentaires