1. ホーム
  2. python

[解決済み] Python 3.8以前のreturn文のstarred iterable unpackingは、なぜ括弧がないと無効な構文なのですか?

2023-06-09 16:12:26

質問

Python言語(特に3.x)では、非常に一般的な 解凍 その簡単な例です。

a, *rest = 1, 2, 3

長年にわたり、この解凍方法は徐々に一般化されてきました(例えば、次のようなものがあります。 PEP 3132 PEP 448 など)、より多くの状況で使用できるようになりました。そのため、Python 3.6 では次のような構文が無効であることを発見して驚きました (Python 3.7 でも同様です)。

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

こんな感じで、返されたタプルを括弧でくくることで動作させることができるんです。

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

で使っているということは return 文の中で使っていることが重要なようです。

t = 1, *rest

は確かに合法で、括弧があってもなくても同じ結果になります。

このケースは単にPythonの開発者が忘れてしまったのか、それともこのケースが無効な構文である理由があるのでしょうか?

私が気になる理由

これは、私がPython言語で持っていると思っていた重要な契約を破ります。次の (これも有効な) 解決策を考えてみてください。

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

通常、このようなコードがある場合、私は t を一時的な名前とみなします。 t をその定義に置き換えるだけで、取り除くことができるはずです。しかし、この場合、これは無効なコードにつながります。

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

もちろん戻り値の周りに括弧を置くことは大したことではありませんが、通常、追加の括弧は複数の可能な結果を区別する(グループ化)ためにのみ必要です。ここでは、括弧を省いても他の不要な動作が発生するわけではなく、むしろ全く動作が発生しないため、このようなことはない。

更新

Python 3.8 以降 ( このリスト を参照)、上で説明した一般化された構文が有効になりました。

どのように解決するのですか?

のコメントから、これは事故だと思われます。 このコミット のコメントから、これは偶然ではないかと思います。

このコミットにより、代入式が testlist_star_expr を取るようになりましたが (これは親子分解を可能にします)、return 文は testlist プロダクションを取るままにしています。私は、コミットがこれを見落としたのではないかと思っています (そしておそらく他の場所もそうですが、私が注目しているのは return_stmt プロダクションに焦点を当てています)。

私は先に進み、これを許可するためにPython Grammar/文法ファイルを修正しました。すべてのテストは合格し続け、その中には test_grammar.py ファイル内のものも含めて、すべてのテストがパスし続けます (しかし、これはひどく網羅的であるとは思えません)。

もしあなたが好奇心旺盛なら これは私が行った変更です . クローンやダウンロードはご自由に 私のフォーク .

UPDATEです。 を投稿しました。 bpo問題 プルリクエスト を追加しました。