Распаковка аргументов: только выраженные аргументы могут следовать за выражением
В Python красиво работает:
def f(x,y,z): return [x,y,z]
a=[1,2]
f(3,*a)
Элементы a
распаковываются, как если бы вы назвали его как f(3,1,2)
, и он возвращает [3,1,2]
. Замечательно!
Но я не могу распаковать элементы a
в первые два аргумента:
f(*a,3)
Вместо того, чтобы называть это как f(1,2,3)
, я получаю "SyntaxError: только аргументы named могут следовать за выражением".
Мне просто интересно, почему это должно быть так, и если есть какой-нибудь умный трюк, который я, возможно, не знал о распаковке массивов в произвольные части списков аргументов, не прибегая к временным переменным.
Ответы
Ответ 1
Как указывает ответ Раймонда Хеттингера, это может измениться в Python 3 и вот связанное предложение, которое было принято.
Особенно, связанный с текущим вопросом, здесь было одно из возможных изменений в этом предложении, которое обсуждалось:
Разрешить выделенное выражение как последний элемент в exprlist. Это упростило бы распаковывая код немного и позволяя выделенному выражению присваивать итератору. Эта поведение было отклонено, потому что это было бы слишком неожиданным.
Итак, есть причины для ограничения с аргументами распаковки функций, но это действительно немного удивительно!
Тем временем, обходной путь, который я искал, очевиден в ретроспективе:
f(*(a+[3]))
Ответ 2
Это не должно быть так. Просто Гвидо считал разумным.
В Python 3 правила для распаковки были несколько либерализованы:
>>> a, *b, c = range(10)
>>> a
0
>>> b
[1, 2, 3, 4, 5, 6, 7, 8]
>>> c
9
В зависимости от того, сможет ли Гвидо улучшить язык, эта либерализация также может быть расширена до функциональных аргументов.
См. обсуждение расширенной итеративной распаковки для некоторых мыслей о том, почему Python 3 изменил правила.
Ответ 3
Благодаря PEP 448 - Дополнительные распаковки обобщений,
f(*a, 3)
является теперь принятым синтаксисом, начиная с Python 3.5. Аналогично, вы можете использовать двунаправленную **
для распараллеливания аргументов аргументов в аргументах где угодно, и один из них можно использовать несколько раз.
Ответ 4
f
ожидает 3 аргумента (x
, y
, z
, в этом порядке).
Предположим L = [1,2]
. Когда вы вызываете f(3, *L)
, что питон делает за кулисами, нужно вызвать f(3, 1, 2)
, не зная длины L
.
Итак, что произойдет, если вместо L
было [1,2,3]
?
Затем, когда вы вызываете f(3, *L)
, вы в конечном итоге вызываете f(3,1,2,3)
, что будет ошибкой, потому что f
ожидает ровно 3 аргумента, и вы дали ему 4.
Теперь предположим, что L=[1,2]1. Look at what happens when you call
f`:
>>> f(3,*L) # works fine
>>> f(*L) # will give you an error when f(1,2) is called; insufficient arguments
Теперь вы неявно знаете, когда вы вызываете f(*L, 3)
, что 3 будет назначено на z
, но python этого не знает. Он знает только, что последние j
многие элементы ввода для f
будут определяться содержимым L
. Но поскольку он не знает значения len(L)
, он не может делать предположений о том, имеет ли f(*L,3)
правильное количество аргументов.
Это, однако, не относится к f(3,*L)
. В этом случае python знает, что все аргументы EXCEPT первого будут определены содержимым L
.
Но если вы назвали аргументы f(x=1, y=2, z=3)
, то аргументы, назначенные по имени, будут связаны сначала. Только тогда связаны позиционные аргументы. Итак, вы делаете f(*L, z=3)
. В этом случае z
сначала привязывается к 3
, а затем остальные значения привязываются.
Теперь интересно, если вы сделали f(*L, y=3)
, это даст вам ошибку для попыток назначить y
дважды (один раз с ключевым словом, еще раз с позицией)
Надеюсь, что это поможет
Ответ 5
Ницца. Это также работает для кортежей. Не забывайте запятую:
a = (1,2)
f(*(a+(3,)))