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