Tuple assignment and generators?

Paul Boddie paul at boddie.org.uk
Fri May 5 13:28:26 CEST 2006


Tim Chase wrote:
>
> I was hoping that there was just some __foo__ property I was
> missing that would have been called in the process of tuple
> unpacking that would allow for a more elegant solution such
> as a generator (or generator method on some object) rather
> than stooping to disassembling opcodes. :)

I suppose you wanted something like this...

a, b, c, d, e = xyz # first, let's consider a plain object

...to use the iterator "protocol" to populate the tuple elements, like
this:

_iter = xyz.__iter__()
a = _iter.next()
b = _iter.next()
c = _iter.next()
d = _iter.next()
e = _iter.next()

For such plain objects, it is possible to use such a mechanism. Here's
a "countdown" iterator:

class A:
    def __init__(self, size):
        self.size = size
    def __iter__(self):
        return B(self.size)

class B:
    def __init__(self, size):
        self.n = size
    def next(self):
        if self.n > 0:
            self.n -= 1
            return self.n
        else:
            raise StopIteration

xyz = A(5)
a, b, c, d, e = xyz

In fact, similar machinery can be used to acquire new values from a
generator:

def g(size):
    while size > 0:
        size = size - 1
        yield size

a, b, c, d, e = g(5)

Note that if the iterator (specifically, the generator in the second
case) doesn't provide enough values, or provides too many, the tuple
unpacking operation will fail with the corresponding exception message.
Thus, generators which provide infinite or very long sequences will not
work unless you discard trailing values; you can support this either by
adding support for slicing to whatever is providing your sequences or,
if you're using generators anyway, by employing an additional
"limiting" generator:

def limit(it, size):
    while size > 0:
        yield it.next()
        size -= 1

xyz = A(5)
a, b, c, d = limit(iter(xyz), 4)

The above generator may be all you need to solve your problem, and it
may be the case that such a generator exists somewhere in the standard
library.

Paul




More information about the Python-list mailing list