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.
2 Answers 2
- 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, []
-
1\$\begingroup\$ Awesome point, didn't realize I can just return a slice and each part of the rest as
None
. Thanks a lot. \$\endgroup\$Samuel Shifterovich– Samuel Shifterovich2016年10月17日 14:59:35 +00:00Commented Oct 17, 2016 at 14:59
The function has no docstring. What does it do? How do I call it? Are there any helpful examples you can present? The text in the post would make a good start.
The name
unpack
is poorly chosen. I know that sequence unpacking is the use case that you have in mind, but the function does not actually unpack anything. What it does is to return a fixed-length prefix of a sequence, padding withNone
if necessary to make it up to the required length. So a name likeprefix_pad_none
would give a clearer indication of the behaviour. (Compare with thepadnone
recipe in theitertools
documentation.)The pad value
None
should be a parameter to the function (with default value ofNone
). That's because there are use cases in which you might want to pad a sequence with some other value. For example, zero, one, and NaN are common pad values in mathematical code.
Revised code:
from itertools import chain, islice, repeat
def prefix_pad(n, iterable, padvalue=None):
"""Return the first n elements of iterable, padded out with padvalue
if iterable has fewer than n elements.
"""
return islice(chain(iterable, repeat(padvalue)), n)
-
\$\begingroup\$ Good point about the name \$\endgroup\$jamylak– jamylak2016年10月18日 03:50:31 +00:00Commented Oct 18, 2016 at 3:50
__iter__
method of your class by thisunpack
(granted you make it return an iterator). \$\endgroup\$__iter__
method, but I would start digging in that direction anyway. \$\endgroup\$