HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMajor

Dynamic unpacking in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
unpackingpythondynamic

Problem

Python lacks dynamic unpacking. Example: You want to unpack a list, let's say coordinates, but don't know whether it contains 3 items or just 2.

x, y, z = [1,2,3] works only if len([x,y,z]) == len([1,2,3]).

x, y, z = [1,2] results in an error. You could add try and except blocks but that could be complicated.

The best option is z being None, as you can simply check using if n is None without any excessive try/except.

So expected result:

>>> x, y, z = unpack([1,2])
>>> print(x)
1
>>> print(y)
2
>>> print(z)
None


My code

def unpack(num, list):
    return_arr = [None] * num
    for i,elem in enumerate(list):
        return_arr[i] = elem
        if i+1 == num:
            return return_arr
    return return_arr


And usage examples:

a,b,c,d = unpack(4, [1,2,3])
print(a),
print(b),
print(c),
print(d),
print("\n")

e,f,g = unpack(3, [1,2,3])
print(e),
print(f),
print(g)


resulting in

1 2 3 None 

1 2 3


You basically have to specify the amount of variables you're unpacking the list to, since the function can't know that.

Solution


  • It is generaly a bad idea to shadow a builtin (like list) by using a variable named after it.



-
You can use slices and array extension to simplify a bit your algorithm:

def unpack(n, lst):
    result = lst[:n]
    return result + [None] * (n - len(result))


-
You can use the itertools module to improve memory management and allow for any iterable:

import itertools

def unpack(n, iterable):
    infinite = itertools.chain(iterable, itertools.repeat(None))
    return itertools.islice(infinite, n)


-
Python 3 has an extended unpacking capability that is closer to your needs:

>>> x, y, *z = [1, 2]
>>> print(x, y, z)
1, 2, []

Code Snippets

def unpack(n, lst):
    result = lst[:n]
    return result + [None] * (n - len(result))
import itertools


def unpack(n, iterable):
    infinite = itertools.chain(iterable, itertools.repeat(None))
    return itertools.islice(infinite, n)
>>> x, y, *z = [1, 2]
>>> print(x, y, z)
1, 2, []

Context

StackExchange Code Review Q#144387, answer score: 20

Revisions (0)

No revisions yet.