Распаковка кортежей Python в операторе return - программирование
Подтвердить что ты не робот

Распаковка кортежей Python в операторе return

Язык 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 (см. пункт 7 в этом списке), обобщенный синтаксис, рассмотренный выше, теперь действует.

4b9b3361

Ответ 1

Я подозреваю, что это авария, основанная на комментариях this commit для Python 3.2.

Это commit разрешало выражению присваивания принимать testlist_star_expr production (что позволяет распаковаться без раздумий), но оставил оператор return, производящий testlist. Я подозреваю, что коммит просто пропустил это (и, возможно, другие места, но сейчас я сосредоточен на производстве return_stmt).

Я пошел дальше и модифицировал файл грамматики/грамматики Python, чтобы это разрешить. Все тесты продолжают проходить, в том числе в файле test_grammar.py (но это не выглядит ужасно исчерпывающим).

Если вам интересно, это изменение, которое я сделал. Не стесняйтесь клонировать или загружать мой вилка.

ОБНОВЛЕНИЕ: Я отправил bpo issue и вытащить запрос для распаковки (и выхода).