How to unpack tuple of length n to m<n variables

Question:

In Python 3 I can do the following (see also PEP3132 on Extended Iterable Unpacking):

a, *b = (1, 2, 3)
# a = 1; b = (2, 3)

What can I do to achieve the same similarly elegant in Python 2.x?


I know that I could use single element access and slicing operations, but I wonder if there is a more pythonic way. My code so far:

a, b = (1, 2, 3)[0], (1, 2, 3)[1:]
# a = 1; b = (2, 3)
Asked By: moooeeeep

||

Answers:

I may be wrong but as far as I know

a, *b = (1, 2, 3)

is just syntactic sugar for slicing and indexing tuples. I find it useful but not very explicit.

Answered By: Félix Cantournet

I don’t think there is any better way than the one you posted but here is an alternative using iter

>>> x = (1,2,3)
>>> i = iter(x)
>>> a,b = next(i), tuple(i)
>>> a
1
>>> b
(2, 3)
Answered By: jamylak

Not sure about the context, but what about .pop(0)?

I see that there are tuples in your example, but if you want to do the sort of stuff you do, lists would be more suited, I think? (Unless there is some good reason for them to be immutable not given in the question.)

b = [1,2,3]
a = b.pop(0)
Answered By: Bittrance

I’ve got this handy little function:

def just(n, seq):
    it = iter(seq)
    for _ in range(n - 1):
        yield next(it, None)
    yield tuple(it)

For example:

a, b, c = just(3, range(5))
print a, b, c
## 0 1 (2, 3, 4)

also works with less arguments:

a, b, c = just(3, ['X', 'Y'])
print a, b, c
## X Y ()

In response to the comment, you can also define:

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

and use it like this:

p = (1,2,3)
a, b = take2(*p)
print a, b
## 1 (2, 3)
Answered By: georg

I found out that the related PEP3132 gives some examples for Python 2.x as well:

Many algorithms require splitting a sequence in a "first, rest" pair:

first, rest = seq[0], seq[1:]

[…]

Also, if the right-hand value is not a list, but an iterable, it has to be converted to a list before being able to do slicing; to avoid creating this temporary list, one has to resort to

it = iter(seq)
first = it.next()
rest = list(it)

Other approaches given in the answers to this question:

Function Argument List Unpacking Approach

requires an extra function definition/call:

def unpack(first, *rest): 
  return first, rest
first, rest = unpack( *seq )

I wonder why it is implemented in unpacking function argument lists but not for normal tuple unpacking.

Generator Approach

Credits. Also requires a custom function implementation. Is a little more flexible concerning the number of first variables.

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)

The most pythonic would probably be the ones mentioned in the PEP above, I guess?

Answered By: moooeeeep
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.