[Python-Dev] syntactic shortcut - unpack to variably sized list

Carlos Ribeiro carribeiro at gmail.com
Thu Nov 18 03:43:39 CET 2004


On Thu, 11 Nov 2004 22:50:21 +0100, Johan Hahn <johahn at home.se> wrote:
> Hi
> 
> As far as I can tell from the archive, this has not been discussed before.
> This is the second time in less than a week that I have stumbled over the rather
> clumsy syntax of extracting some elements of a sequence and at the same time
> remove those from the sequence:
> >>> L = 'a b 1 2 3'.split(' ')
> >>> a,b,L = L[0], L[1], L[2:]

I am really late on this thread, but anyway, I've come up with another
approach to solve the problem using iterators. It uses iterator that
is guaranteed to always return a fixed number of elements, regardless
of the size of the sequence; when it finishes, it returns the tail of
the sequence as the last argument. This is a simple-minded proof of
concept, and it's surely highly optimizable in at least a hundred
different ways :-)

def iunpack(seq, times, defaultitem=None):
    for i in range(times):
       if i < len(seq):
           yield seq[i]
       else:
           yield defaultitem
    if i < len(seq):
        yield seq[i+1:]
    else:
        yield ()

Usage is as follows:

>>> tuple(iunpack((1,2,3,4), 1))
(1, (2, 3, 4))
>>> tuple(iunpack((1,2,3,4), 2))
(1, 2, (3, 4))
>>> tuple(iunpack((1,2,3,4), 4))
(1, 2, 3, 4, ())
>>> tuple(iunpack((1,2,3,4), 6))
(1, 2, 3, 4, None, None, ())

As it is, it fails if the requested number of elements is zero, but
this is not a real use case for it anyway. But the best part is yet to
come. Because of the way Python implicitly packs & unpacks tuples, you
can use it *without* calling tuple():

>>> a,b = iunpack((1,2,3,4), 1)
>>> a,b
(1, (2, 3, 4))
>>> a,b,c = iunpack((1,2,3,4), 2)
>>> a,b,c
(1, 2, (3, 4))
>>> a,b,c,d,e = iunpack((1,2,3,4), 4)
>>> a,b,c,d,e
(1, 2, 3, 4, ())
>>> a,b,c,d,e,f,g = iunpack((1,2,3,4), 6)
>>> a,b,c,d,e,f,g
(1, 2, 3, 4, None, None, ())

The only catch is that, if you have only one parameter, then all you
will get is the generator itself.

>>> a = iunpack((1,2,3,4), 1)
>>> a
<generator object at 0x4071bfac>

But that's a corner case, and not the intended use anyway. Besides
that, there is an issue regarding the 'times' parameter; whether it
should return 'times' items plus the tail part, or 'times-1' items and
the tail part. I think that it's fine the way it is.

-- 
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: carribeiro at gmail.com
mail: carribeiro at yahoo.com


More information about the Python-Dev mailing list