是否有接受复杂哨兵的迭代器?
Is there an iter which accepts a complex 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'
但可以想象它们与其他值交错的情况)。
本质上我是在寻找一种更复杂的sentinel的使用方法有这样的概念吗?
我知道我可以求助于 , hovewer @HappyLeapSecond answer is so elegant I would like to keep the spirit (I went though itertools
中提到的明显但丑陋的代码,但是 none 可用的方法似乎可以完成这项工作)
您可以将 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)
创建了一个复杂的谓词函数,它将在三的第三个倍数处停止迭代。在你的情况下,
I would like to have it end after getting, say, a total of two 'END'
你可以使用 create_predicate(lambda elem: elem == 'END', 2)
.
可以使用生成器来完成:
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
我认为这使事情变得相当简单(对于您的用例来说可能太简单了,但您的示例非常简单)。
我使用带有两个参数的 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'
但可以想象它们与其他值交错的情况)。
本质上我是在寻找一种更复杂的sentinel的使用方法有这样的概念吗?
我知道我可以求助于 itertools
中提到的明显但丑陋的代码,但是 none 可用的方法似乎可以完成这项工作)
您可以将 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)
创建了一个复杂的谓词函数,它将在三的第三个倍数处停止迭代。在你的情况下,
I would like to have it end after getting, say, a total of two
'END'
你可以使用 create_predicate(lambda elem: elem == 'END', 2)
.
可以使用生成器来完成:
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
我认为这使事情变得相当简单(对于您的用例来说可能太简单了,但您的示例非常简单)。