I was recently surprised to find that the "splat" (unary *) operator always captures slices as a list
during item unpacking, even when the sequence being unpacked has another type:
>>> x, *y, z = tuple(range(5))
>>> y
[1, 2, 3] # list, was expecting tuple
Compare to how this assignment would be written without unpacking:
>>> my_tuple = tuple(range(5))
>>> x = my_tuple[0]
>>> y = my_tuple[1:-1]
>>> z = my_tuple[-1]
>>> y
(1, 2, 3)
It is also inconsistent with how the splat operator behaves in function arguments:
>>> def f(*args):
... return args, type(args)
...
>>> f()
((), <class 'tuple'>)
In order to recover y
as a tuple after unpacking, I now have to write:
>>> x, *y, z = tuple(range(5))
>>> y = tuple(y)
Which is still much better that the slice-based syntax, but nonetheless suffers from what I consider to be a very unnecessary and unexpected loss of elegance. Is there any way to recover y
as a tuple instead of a list without post-assignment processing?
I tried to force python to interpret y
as a tuple by writing x, *(*y,), z = ...
, but it still ended up as a list. And of course silly things like x, *tuple(y), z
don't work in python.
I am currently using Python 3.8.3 but solutions/suggestions/explanations involving higher versions (as they become available) are also welcome.
y
is a tuple, does this limit you in any way? As far as I can tell, in duck-typing fashion, anywhere a tuple is expected, you can substitute it with a list. – Sandwichx, *y, z = tuple(range(5))
is equivalent tox, *y, z = range(5)
, so you could at least avoid repeatingtuple
twice by dropping it from the first statement. – Arching