是否有接受复杂哨兵的iter?

时间:2015-07-14 12:48:30

标签: python iterator sentinel

我使用iter有两个参数,并且想知道是否有一个等价物可以接受更复杂的哨兵?

例如,在下面的代码中

# returns digits 1 to 10 upon subsequently calling .create(), 
# then returns 'END' each time afterwards
class MyClass:
    def __init__(self):
        self.counter = 0
    def create(self):
        self.counter += 1
        if self.counter > 10:
            return 'END'
        else:
            return self.counter

c = MyClass()
for i in iter(c.create, 'END'):
    print(i)

迭代在获得'END'后结束。比如说,总共有两个'END'(不一定是一个接一个 - 上面的代码在前十个调用之后只生成'END',但我可以想象一个他们与其他价值观交织的情况)。

从本质上讲,我正在寻找一种使用更复杂的哨兵的方法。是否有这样的概念?

我知道我可以诉诸previous question中提到的明显但丑陋的代码,hovewer @HappyLeapSecond答案是如此优雅我想保持精神(我虽然itertools但是没有可用的方法似乎可以完成这项工作)

2 个答案:

答案 0 :(得分:1)

您可以将itertools.takewhile与有状态predicate一起使用。例如:

>>> from itertools import takewhile
>>> def create_predicate(func, max_count):
    """Return False only when func evaluates True for the max_count time."""
    def predicate(elem):
        if func(elem):
            predicate.count += 1
        if predicate.count == max_count:
            return False
        return True
    predicate.count = 0
    return predicate

>>> list(takewhile(create_predicate(lambda elem: elem % 3 == 0, 3), range(1, 20)))
[1, 2, 3, 4, 5, 6, 7, 8]

在上面的示例中,create_predicate(lambda elem: elem % 3 == 0, 3)创建了一个复杂的谓词函数,该函数将停止迭代三次的三次。在你的情况下,

  

我希望在获得总共两个'END'

后结束

您可以使用create_predicate(lambda elem: elem == 'END', 2)

答案 1 :(得分:0)

可以使用发电机完成:

class MyClass:
    def __init__(self):
        self.counter = 0
    def create(self, func, number):
        while number:
            self.counter += 1
            if func(self.counter):
                yield 'END'
                number -= 1
            else:
                yield self.counter

以下是它的工作原理:

>>> def foo(n):
    return n % 3 == 0
>>> c = MyClass()
>>> for i in c.create(foo, 3):
    print(i)

1
2
END
4
5
END
7
8
END

我认为这可以使事情变得相当简单(对于您的用例可能过于简单,但您的示例非常简单)。