Python 3.4嵌套循环使用lambda过滤器奇怪地工作

时间:2015-04-27 19:13:51

标签: python loops python-3.x lambda

我正在尝试使用NLTK的短语代码(https://github.com/nltk/nltk/blob/develop/nltk/tokenize/texttiling.py)。

它是根据文档内容将文档输入分割成几个图块的代码。我注意到,通过将整个文本作为一个图块返回,平铺对于某些文档根本不起作用,并且发现这部分代码工作很奇怪。

    depth_tuples = sorted(zip(depth_scores, range(len(depth_scores))))
    depth_tuples.reverse()
    hp = filter(lambda x:x[0]>cutoff, depth_tuples)

    for dt in hp:
        boundaries[dt[1]] = 1
        for dt2 in hp: #undo if there is a boundary close already
            if dt[1] != dt2[1] and abs(dt2[1]-dt[1]) < 4 \
                   and boundaries[dt2[1]] == 1:
                boundaries[dt[1]] = 0
    return boundaries

Depth_tuple是一个包含元组列表[(score,index)]的列表,而hp是一个过滤结果,其得分大于某个截止值。

使用嵌套循环,它为hp的每个条目分别迭代hp两次。换句话说,对于hp的每个条目,它应检查hp的所有条目的某些内容。但是我注意到在第一次迭代后没有执行第二个循环(对于hp中的dt2)。它就像dt2指针在第一个dt的hp末尾到达,并且它没有为新的迭代初始化。

为您提供此现象的简化示例, 比如x = [(0.6,3),(0.2,1),(0.5,2),(0.4,3)]

如果截止值为0.3,则hp包含[(0.6,3),(0.5,2),(0.4,3)]

所以循环应该像

当x =(0.6,3)时,第二个循环检查[(0.6,3),(0.5,2),(0.4,3)]

当x =(0.5,2)时,第二个循环再次检查[(0.6,3),(0.5,2),(0.4,3)]

但它仅在x =(0.6,3)时才这样做,而对于x的其余部分,第二个循环不会运行。

我最初怀疑迭代器已经在第二个循环中到达了hp的末尾,但是它不能解释第一个循环的hp中的迭代器如何仍然可以...

你能解释一下为什么会这样吗?谢谢!

2 个答案:

答案 0 :(得分:5)

您正在使用Python 3,并且该配方是为Python 2编写的。在Python 2中,filter返回list,显然可以使用{{1}多次迭代(内部for)。

但是在Python 3中,for dt2 in hp将为a one-pass iterator;现在,外部hp将消耗第一个元素,内部for将消耗所有剩余元素;当内循环退出时,外循环找到一个空迭代器并退出。

或者,正如Python 2和3文档所述,在Python 2中for等同于列表理解

filter(function, iterable)

并且在Python 3中,它等同于生成器表达式

[item for item in iterable if function(item)]

作为最简单的修复,将(item for item in iterable if function(item)) 返回的迭代器放入filter

list

答案 1 :(得分:2)

我不知道为什么Dan D.删除his answer。也许它没有完全解释这个问题,但它确实提供了正确的解决方案以及您所缺少的关键信息。

假设这是Python 3,filter返回iterator,而不是序列。迭代器只能迭代一次。迭代器知道它的当前位置&#34;,并在你要求时懒得产生值;一旦你要求所有的价值观,就没有更多的价值可以给予。所以,例如:

>>> hp = iter([1,2,3])
>>> for dt in hp:
...     print(dt)
1
2
3
>>> for dt in hp:
...     print(dt)

第二次,它没有打印任何内容,因为您已经使用了所有值。

同样的事情发生在嵌套循环中:

>>> for dt in hp:
...     print(dt)
...     for dt in hp:
...         print('>', dt)
1
> 2
> 3

在通过外循环的第一次迭代中,dt获得第一个值。然后嵌套的内部循环获取所有其余值,因此外部循环完成。

如果你想反复迭代某些东西,最简单的方法就是把它转换成一个序列:

hp = list(hp)

在某些情况下,使用tee可能更有效和/或在概念上更清晰,但这并不适用于此处。您的代码旨在将hp视为序列,因此只需将其作为序列。