【问题标题】:Is there an iter which accepts a complex sentinel?是否有一个接受复杂哨兵的迭代器?
【发布时间】:2015-10-03 02:46:59
【问题描述】:

我使用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 中提到的明显但丑陋的代码,但是@HappyLeapSecond 的答案是如此优雅,我想保持这种精神(我去了itertools,但没有可用的方法似乎完成了这项工作)

【问题讨论】:

    标签: python iterator sentinel


    【解决方案1】:

    可以使用生成器来完成:

    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
    

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

    【讨论】:

      【解决方案2】:

      您可以将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)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-11
        • 2022-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-10
        • 2021-01-07
        相关资源
        最近更新 更多