Как распаковать кортеж длины n до m <n переменных
В Python 3 я могу сделать следующее (см. также PEP3132 в расширенном распакованном распаковке):
a, *b = (1, 2, 3)
# a = 1; b = (2, 3)
Что я могу сделать для достижения такого же элегантного в Python 2.x?
Я знаю, что я мог бы использовать операции доступа к единому элементу и нарезки, но мне интересно, есть ли более питонический путь. Мой код:
a, b = (1, 2, 3)[0], (1, 2, 3)[1:]
# a = 1; b = (2, 3)
Ответы
Ответ 1
Я узнал, что связанный PEP3132 дает некоторые примеры для Python 2.x:
Многие алгоритмы требуют разбиения последовательности в паре "первый, отдых":
first, rest = seq[0], seq[1:]
[...]
Кроме того, если правое значение не является списком, но является итерируемым, оно должно быть преобразовано в список, прежде чем сможет выполнять нарезку; чтобы избежать создания этого временного списка, нужно прибегнуть к
it = iter(seq)
first = it.next()
rest = list(it)
Другие подходы, приведенные в ответах на этот вопрос:
Список аргументов функции Распаковка
требуется дополнительное определение/вызов функции:
def unpack(first, *rest):
return first, rest
first, rest = unpack( *seq )
Интересно, почему он реализован в распаковке списков аргументов функции, но не для обычной распаковки кортежей.
Подход генератора
Кредиты. Также требуется реализация пользовательских функций. Несколько более гибко относится к числу первых переменных.
def unpack_nfirst(seq, nfirst):
it = iter(seq)
for x in xrange(nfirst):
yield next(it, None)
yield tuple(it)
first, rest = unpack_nfirst(seq, 1)
Возможно, большинство питонов, возможно, были упомянуты в PEP выше?
Ответ 2
У меня есть эта небольшая функция:
def just(n, seq):
it = iter(seq)
for _ in range(n - 1):
yield next(it, None)
yield tuple(it)
Например:
a, b, c = just(3, range(5))
print a, b, c
## 0 1 (2, 3, 4)
также работает с меньшими аргументами:
a, b, c = just(3, ['X', 'Y'])
print a, b, c
## X Y ()
В ответ на комментарий вы также можете определить:
def take2(a, *rest): return a, rest
def take3(a, b, *rest): return a, b, rest
def take4(a, b, c, *rest): return a, b, rest
... etc
и используйте его следующим образом:
p = (1,2,3)
a, b = take2(*p)
print a, b
## 1 (2, 3)
Ответ 3
Я не думаю, что есть лучший способ, чем тот, который вы опубликовали, но вот альтернатива, используя iter
>>> x = (1,2,3)
>>> i = iter(x)
>>> a,b = next(i), tuple(i)
>>> a
1
>>> b
(2, 3)
Ответ 4
Возможно, я ошибаюсь, но насколько я знаю
a, *b = (1, 2, 3)
- это просто синтаксический сахар для нарезки и индексирования кортежей. Я считаю это полезным, но не очень явным.
Ответ 5
Не уверен в контексте, но как насчет .pop(0)?
Я вижу, что в вашем примере есть кортежи, но если вы хотите сделать то, что делаете, списки будут более подходящими, я думаю? (Если нет веских оснований для того, чтобы они были неизменными, не заданными в вопросе.)
b = [1,2,3]
a = b.pop(0)