inverse of izip
Peter Otten
__peter__ at web.de
Thu Aug 19 14:55:45 EDT 2004
Steven Bethard wrote:
> Peter Otten <__peter__ at web.de> wrote in message
> news:<cg1pct$p58$00$1 at news.t-online.com>...
>> However, your sample data is badly chosen. Unless I have made a typo
>> repeating your demo, you are getting the same (last) sequence twice due
>> to late binding of i.
>>
> [snip]
>> >>> map(list, starzip(it.izip("123", "abc")))
>> [['1', '2', '3'], ['a', 'b', 'c']]
>> >>> x, y = starzip(it.izip("123", "abc"))
>> >>> list(x)
>> ['a', 'b', 'c']
>> >>> list(y)
>> ['a', 'b', 'c']
>> >>>
>
> I knew there was something funny about binding in generators, but I
> couldn't remember what... Could you explain why 'map(list, ...)'
> works, but 'x, y = ...' doesn't? I read the PEP, but I'm still not
> clear on this point.
Maybe the following example can illustrate what I think is going on:
import itertools as it
def starzip(iterables):
return ((t[i] for t in itr)
for (i, itr) in
enumerate(it.tee(iterables)))
# the order of calls equivalent to map(list, starzip(...))
s = starzip(it.izip("abc", "123"))
x = s.next()
# the local variable i in starzip() shared by x and y
# is now 0
print x.next(),
print x.next(),
print x.next()
y = s.next()
# i is now 1, but because no further calls to x.next()
# will occur it doesn't matter
print y.next(),
print y.next(),
print y.next()
s = starzip(it.izip("abc", "123"))
x = s.next() # i is 0
y = s.next() # i is 1
# both x an y yield t[1]
print x.next(),
print x.next(),
print x.next()
print y.next(),
print y.next(),
print y.next()
You can model the nested generator expressions' behaviour with the following
function - which I think is much clearer.
def starzip(iterables):
def inner(itr):
for t in itr:
yield t[i]
for (i, itr) in enumerate(it.tee(iterables)):
yield inner(itr)
Note how itr is passed explicitly, i. e. it is not affected by later
rebindings in startzip() whereas i is looked up in inner()'s surrounding
namespace at every yield.
Peter
More information about the Python-list
mailing list