2015-07-14 5 views
1

Я использую 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, но ни один из доступных методов не кажется, делает работа)

ответ

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).

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 

Я думаю, что это держит вещи довольно простые (возможно, слишком просто для случая использования, но ваш пример довольно просто).