DEV Community

Vladislav Zenin
Vladislav Zenin

Posted on • Updated on • Originally published at python-traceback.com

Tricky Unpacking In Python

Imagine, you iterate through a collection, which contains some other collections.

Like so: list of lists

In [32]: L = [ [i] for i in range(10) ]

In [33]: L
Out[33]: [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]
Enter fullscreen mode Exit fullscreen mode

One obvious way to iterate over inner values is to use indexing:

In [24]: [ i[0] for i in L ]
Out[24]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Enter fullscreen mode Exit fullscreen mode

Well, there is another way to do so. Almost so :)

In [24]: [ i for i, in L ]
Out[24]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Enter fullscreen mode Exit fullscreen mode

In fact, it is single element unpacking. It works, because in python commas "construct" tuples, not brackets

In [29]: 5,
Out[29]: (5,)

In [30]: (5)
Out[30]: 5
Enter fullscreen mode Exit fullscreen mode

Are there any differences?

Yeap.

This unpacking seems to be faster than reading by index. Not much, by ~10%.

In [24]: L = [ [i] for i in range(1000) ]

In [25]: %timeit [ i for i, in L ]
19.7 µs ± 31.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [26]: %timeit [ i[0] for i in L ]
22.1 µs ± 150 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Enter fullscreen mode Exit fullscreen mode

Also, there is logical difference.

If we take a list of empty lists as input, both statements will fall with different exceptions:

In [30]: [ i[0] for i in L+[[]] ]
# IndexError: list index out of range

In [31]: [ i for i, in L+[[]] ]
# ValueError: not enough values to unpack (expected 1, got 0)
Enter fullscreen mode Exit fullscreen mode

However, if we have more than 1 element in any of inner lists, then:

  • unpacking will fall with ValueError: too many values to unpack (expected 1)
  • and reading by index will silently return first elements of lists

"Explicit is better than implicit" - they say, huh?

Hope you enjoyed! :)

Top comments (0)