理解Python3.x中的izip

2024-05-13 01:30:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我的问题只是为了学习目的,而且只在python3.x上。在现实生活中,我将使用zip,因为python3zip的作用与python2-izip相同(即返回一个生成器,而不是真正的东西)。在

在python2中,izip本质上等同于下面的代码(从izip中选取,加上一些调试代码)

def izip(*iterables):
    iterators = map(iter, iterables)
    n = 0
    while iterators:
        x = tuple(map(next, iterators))
        print("at n={}, x={} ".format(n, x))
        yield x
        n += 1
        if n > 10: break

Python2很好。izip('abc', 'ABC')的输出是:

^{pr2}$

Python3进入了一个无限循环。原因在this thread中解释。但还有一点我无法理解:python3只产生第一个元组。这是同一程序的输出。为什么bs和cs没有出现?公司名称:

at n=0, x=('a', 'A') 
('a', 'A')
at n=1, x=() 
()
at n=2, x=() 
()
at n=3, x=() 
() etc.

我的两个问题是为什么Python会这样?如何让这些代码生效呢?在


Tags: 代码目的mapdefzipatpython3iterators
1条回答
网友
1楼 · 发布于 2024-05-13 01:30:51

问题在于python2和python3之间map的不同行为,特别是在对mapiterators = map(iter, iterables))的第一次调用中。在

在python3中,map返回生成器(或类似生成器的对象),而在python2中,它是一个列表。这意味着在第一次调用tuple(map(next, iterators))之后,iterators生成器将被完全消耗,因此在下一次迭代中,不再需要再使用迭代器了。在

如果你改变了:

iterators = map(iter, iterables) 

收件人:

^{pr2}$

(这可以说是更好的iterators = [ iter(it) for it in iterables ]


正如您所指出的,它现在进入了一个无限循环。同样,问题在于map函数,但这次是在第二次调用中。在

首先,让我们了解这个实现在python2中是如何工作的。尽管有一个while iterators循环,但循环不会因条件为false而中断,而是由于对next的一个调用引发StopIteration异常。此异常被传播到调用方的循环,它正确地理解不再有结果。在

这样执行可能会很直观:

def izip(*iterables):
    if not iterables: return []
    iterators = map(iter, iterables)
    while True:
        yield tuple(map(next, iterators))

现在,map的行为在python3中也发生了变化。它不是提高产量,而是“削减”产出:

list(map(next, [ iter('ab'), iter('') ]))
=> ['a']

不引发StopIteration会导致无限循环。在

解决方案是使用列表理解,它会传播StopIteration异常。在

def izip(*iterables):
    if not iterables: return []
    iterators = map(iter, iterables)
    while True:
        yield tuple([ next(it) for it in iterators ])

经验教训:列出理解(和生成器表达式)should be favoredover mapfilter,等等

相关问题 更多 >