52 votes

Comment a changé print(*a, a.pop(0)) ?

Ce code :

a = [1, 2, 3]
print(*a, a.pop(0))

Python 3.8 imprime 2 3 1 (est-ce que le pop avant le déballage).
Python 3.9 imprime 1 2 3 1 (est-ce que le pop après le déballage).

Qu'est-ce qui a provoqué ce changement ? Je ne l'ai pas trouvé dans le journal des modifications .

Edit : Pas seulement dans les appels de fonction mais aussi par exemple dans une affichage de la liste :

a = [1, 2, 3]
b = [*a, a.pop(0)]
print(b)

Imprimés [2, 3, 1] vs [1, 2, 3, 1] . Et Listes d'expressions dit "Les expressions sont évaluées de gauche à droite" (c'est le lien vers la documentation de Python 3.8), donc je m'attendrais à ce que l'expression de déballage se produise en premier.

47voto

user2357112 Points 37737

Je soupçonne qu'il s'agit d'un accident, mais je préfère le nouveau comportement.

Ce nouveau comportement est la conséquence d'une modification de la façon dont le bytecode de l'application * les arguments fonctionnent. Le changement se situe dans le journal des modifications sous Python 3.9.0 alpha 3 :

bpo-39320 : Remplacer quatre bytecodes complexes pour construire des séquences par trois plus simples.

Les quatre bytecodes suivants ont été supprimés :

  • CONSTRUIRE_LISTE_DÉBALLER
  • CONSTRUIRE_TUPLE_DÉBALLER
  • CONSTRUIRE_SET_DÉBALLER
  • CONSTRUIRE_TUPLE_DÉBALLER_AVEC_APPEL

Les trois bytecodes suivants ont été ajoutés :

  • LIST_TO_TUPLE
  • LIST_EXTEND
  • SET_UPDATE

Sous Python 3.7 (je n'ai pas de version 3.8 à tester), le bytecode de la fonction f(*a, a.pop()) ressemble à ça :

  1           0 LOAD_NAME                0 (f)
              2 LOAD_NAME                1 (a)
              4 LOAD_NAME                1 (a)
              6 LOAD_METHOD              2 (pop)
              8 CALL_METHOD              0
             10 BUILD_TUPLE              1
             12 BUILD_TUPLE_UNPACK_WITH_CALL     2
             14 CALL_FUNCTION_EX         0
             16 RETURN_VALUE

alors que sur 3.9, ça ressemble à ça :

  1           0 LOAD_NAME                0 (f)
              2 BUILD_LIST               0
              4 LOAD_NAME                1 (a)
              6 LIST_EXTEND              1
              8 LOAD_NAME                1 (a)
             10 LOAD_METHOD              2 (pop)
             12 CALL_METHOD              0
             14 LIST_APPEND              1
             16 LIST_TO_TUPLE
             18 CALL_FUNCTION_EX         0
             20 RETURN_VALUE

Dans l'ancien bytecode, le code pousse a y (a.pop(),) sur la pile, puis dépaquette ces deux itérables en un tuple. Dans le nouveau bytecode, le code pousse une liste sur la pile, puis fait l.extend(a) y l.append(a.pop()) puis appelle tuple(l) .

Ce changement a pour effet de décaler le déballage de l'article a avant le pop mais cela ne semble pas avoir été délibéré. En regardant bpo-39320 l'intention était de simplifier les instructions du bytecode, pas de changer le comportement, et le fil de discussion de bpo n'a aucune discussion sur les changements de comportement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X