疲惫的迭代器 - 怎么办呢?

时间:2010-10-15 06:47:53

标签: python filter iterator python-3.x

(在Python 3.1中) (与another question I asked有些相关,但这个问题是关于迭代器的用尽。)

# trying to see the ratio of the max and min element in a container c
filtered = filter(lambda x : x is not None and x != 0, c)
ratio = max(filtered) / min(filtered)

我花了半个小时才意识到问题是什么(过滤器返回的迭代器在到达第二个函数调用时已经耗尽)。如何以最Pythonic /规范的方式重写它?

此外,除了获得更多经验之外,我还能做些什么来避免此类错误? (坦率地说,我不喜欢这种语言功能,因为这些类型的错误很容易制作,很难捕捉到。)

4 个答案:

答案 0 :(得分:7)

itertools.tee功能可以在这里提供帮助:

import itertools

f1, f2 = itertools.tee(filtered, 2)
ratio = max(f1) / min(f2)

答案 1 :(得分:5)

只需调用tuple(iterator)就可以将迭代器转换为元组

但是我会将该过滤器重写为列表理解,看起来像这样

# original
filtered = filter(lambda x : x is not None and x != 0, c)

# list comp
filtered = [x for x in c if x is not None and x != 0]

答案 2 :(得分:5)

实际上你的代码引发了一个可以防止这个问题的异常!所以我猜问题是你掩盖了异常?

>>> min([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence
>>> min(x for x in ())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence

无论如何,您还可以编写一个新功能,同时为您提供最小值和最大值:

def minmax( seq ):
    " returns the `(min, max)` of sequence `seq`"
    it = iter(seq)
    try:
        min = max = next(it)
    except StopIteration:
        raise ValueError('arg is an empty sequence')
    for item in it:
        if item < min:
            min = item
        elif item > max:
            max = item
    return min, max

答案 3 :(得分:3)

实体filtered本质上是一个具有状态的对象。当然,现在很明显,在其上运行maxmin会改变该状态。为了停止对它的绊倒,我喜欢绝对清楚(对我自己,真的)我构建某些东西,而不仅仅是转换

添加额外的步骤确实有帮助:

def filtered(container):
    return filter(lambda x : x is not None and x != 0, container)

ratio = max(filtered(c)) / min(filtered(c))

你是否将filtered(...)置于某个函数中(可能它不需要其他任何东西)或将其定义为模块级函数取决于你,但在这种情况下我建议if {{ 1}}(迭代器)只在函数中需要,留在那里直到你在其他地方需要它。

你可以做的另一件事是从它构造一个filtered,它将评估迭代器:

list

(当然,你可以说filtered_iter = filter(lambda x : x is not None and x != 0, container) filtered = list(filtered_iter) ratio = max(filtered) / min(filtered) 。)