Extended tuple unpacking in Python 2
Asked Answered
E

5

30

Is it possible to simulate extended tuple unpacking in Python 2?

Specifically, I have a for loop:

for a, b, c in mylist:

which works fine when mylist is a list of tuples of size three. I want the same for loop to work if I pass in a list of size four.

I think I will end up using named tuples, but I was wondering if there is an easy way to write:

for a, b, c, *d in mylist:

so that d eats up any extra members.

Ethanol answered 17/3, 2011 at 1:5 Comment(4)
#10300182 generalWestbrook
https://mcmap.net/q/375613/-how-to-separate-output-data specialWestbrook
#20501940 specialWestbrook
#749570 specialWestbrook
I
14

You could define a wrapper function that converts your list to a four tuple. For example:

def wrapper(thelist):
    for item in thelist:
        yield(item[0], item[1], item[2], item[3:])

mylist = [(1,2,3,4), (5,6,7,8)]

for a, b, c, d in wrapper(mylist):
    print a, b, c, d

The code prints:

1 2 3 (4,)
5 6 7 (8,)
Interplanetary answered 17/3, 2011 at 1:14 Comment(1)
Today you can do a, b, *c = (1, 2, 3) or a, b, *c = (1, 2) or a, b*, c = (1, 2, 3, 4) -- the * variable is always a list that defaults to empty. It will contain any 'extra' items not captured.Flung
D
22

You can't do that directly, but it isn't terribly difficult to write a utility function to do this:

>>> def unpack_list(a, b, c, *d):
...   return a, b, c, d
... 
>>> unpack_list(*range(100))
(0, 1, 2, (3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99))

You could apply it to your for loop like this:

for sub_list in mylist:
    a, b, c, d = unpack_list(*sub_list)
Debbiedebbra answered 17/3, 2011 at 1:25 Comment(0)
I
14

You could define a wrapper function that converts your list to a four tuple. For example:

def wrapper(thelist):
    for item in thelist:
        yield(item[0], item[1], item[2], item[3:])

mylist = [(1,2,3,4), (5,6,7,8)]

for a, b, c, d in wrapper(mylist):
    print a, b, c, d

The code prints:

1 2 3 (4,)
5 6 7 (8,)
Interplanetary answered 17/3, 2011 at 1:14 Comment(1)
Today you can do a, b, *c = (1, 2, 3) or a, b, *c = (1, 2) or a, b*, c = (1, 2, 3, 4) -- the * variable is always a list that defaults to empty. It will contain any 'extra' items not captured.Flung
A
11

For the heck of it, generalized to unpack any number of elements:

lst = [(1, 2, 3, 4, 5), (6, 7, 8), (9, 10, 11, 12)]

def unpack(seq, n=2):
    for row in seq:
        yield [e for e in row[:n]] + [row[n:]]

for a, rest in unpack(lst, 1):
    pass

for a, b, rest in unpack(lst, 2):
    pass

for a, b, c, rest in unpack(lst, 3):
    pass
Argyll answered 17/3, 2011 at 1:23 Comment(0)
D
0

You can write a very basic function that has exactly the same functionality as the python3 extended unpack. Slightly verbose for legibility. Note that 'rest' is the position of where the asterisk would be (starting with first position 1, not 0)

def extended_unpack(seq, n=3, rest=3):
    res = []; cur = 0
    lrest = len(seq) - (n - 1)    # length of 'rest' of sequence
    while (cur < len(seq)):
        if (cur != rest):         # if I am not where I should leave the rest
            res.append(seq[cur])  # append current element to result
        else:                     # if I need to leave the rest
            res.append(seq[cur : lrest + cur]) # leave the rest
            cur = cur + lrest - 1 # current index movded to include rest
        cur = cur + 1             # update current position
     return(res)
Dryden answered 1/4, 2019 at 0:37 Comment(0)
R
0

Python 3 solution for those that landed here via an web search:

You can use itertools.zip_longest, like this:

from itertools import zip_longest

max_params = 4

lst = [1, 2, 3, 4]
a, b, c, d = next(zip(*zip_longest(lst, range(max_params))))
print(f'{a}, {b}, {c}, {d}') # 1, 2, 3, 4

lst = [1, 2, 3]
a, b, c, d = next(zip(*zip_longest(lst, range(max_params))))
print(f'{a}, {b}, {c}, {d}') # 1, 2, 3, None

For Python 2.x you can follow this answer.

Roshan answered 29/9, 2020 at 21:10 Comment(4)
Why not just use extended tuple unpacking like I did in the question?Ethanol
I feel like I should delete these old Python 2 questionsEthanol
@NeilG extended tuple unpacking works too (partly the reason I upvoted your question), I just came up with this, and thought it'd be nice to share. Hmm I am not sure about deleting the question just because it's Python 2 - if Python 2 questions should be deleted, then it would better be discussed in Meta first IMHO. :)Roshan
You're right. I'd like to have a banner that says "STOP USING PYTHON 2", but I guess someone would edit that out of the question.Ethanol

© 2022 - 2024 — McMap. All rights reserved.