web-dev-qa-db-fra.com

Python Décompression de tuple dans l'instruction return

Le langage Python (en particulier 3.x) permet un déballage très général des itérables, dont un exemple simple est

a, *rest = 1, 2, 3

Au fil des ans, ce déballage s'est progressivement généralisé (voir par exemple PEP 3132 et PEP 448 ), ce qui lui permet d'être utilisé dans de plus en plus de circonstances. En tant que tel, j'ai été surpris de découvrir que la syntaxe suivante n'est pas valide dans Python 3.6 (et le reste dans Python 3.7):

def f():
    rest = [2, 3]
    return 1, *rest  # Invalid

Je peux le faire fonctionner en encapsulant le Tuple retourné entre parenthèses comme ceci:

def f():
    rest = [2, 3]
    return (1, *rest)  # Valid

Le fait que j'utilise ceci dans une instruction return semble être important, car

t = 1, *rest

est en effet légal et se traduit par le même avec et sans parenthèses.

Ce cas a-t-il simplement été oublié par les développeurs Python, ou y a-t-il une raison pour laquelle ce cas n'est pas une syntaxe valide?

Pourquoi je m'en soucie

Cela rompt un contrat important que je pensais avoir avec le langage Python. Considérez la solution suivante (également valide):

def f():
    rest = [2, 3]
    t = 1, *rest
    return t

Normalement, quand j'ai un code comme celui-ci, je considère que t est un nom temporaire, dont je devrais pouvoir me débarrasser en remplaçant simplement t dans la ligne de fond par sa définition. Dans ce cas cependant, cela conduit au code invalide

def f():
    rest = [2, 3]
    return 1, *rest

Bien sûr, ce n'est pas grave d'avoir à placer des parenthèses autour de la valeur de retour, mais généralement des parenthèses supplémentaires ne sont nécessaires que pour faire la distinction entre plusieurs résultats possibles (regroupement). Ici, ce n'est pas le cas, car la suppression des parenthèses ne produit pas d'autres comportements indésirables, mais plutôt aucun comportement du tout.

63
jmd_dk

Je soupçonne que c'est un accident, basé sur les commentaires de ce commit pour Python 3.2.

Cette validation a permis à l'expression d'affectation de prendre un testlist_star_expr production (ce qui permet le décompactage non entre parenthèses), mais a laissé l'instruction return en prenant une production testlist. Je soupçonne que le commit vient de manquer cela (et peut-être d'autres endroits, mais je me concentre sur le return_stmt production pour l'instant).

Je suis allé de l'avant et j'ai modifié le fichier Python Grammar/Grammar pour permettre cela. Tous les tests continuent de passer, y compris ceux du test_grammar.py fichier (mais cela ne semble pas terriblement exhaustif).

Si vous êtes curieux, c'est le changement que j'ai fait . N'hésitez pas à cloner ou à télécharger ma fourchette .

MISE À JOUR: J'ai envoyé un problème bpo et un pull request pour le retour (et rendement) déballage.

29
David Cuthbert