Уступая, пока все необходимые значения не будут получены, есть ли способ сделать срез, чтобы стать ленивым - PullRequest
3 голосов
/ 24 июля 2010

Есть ли способ прекратить давать, когда генератор не закончил значения и все необходимые результаты были прочитаны?Я имею в виду, что генератор дает значения, даже не делая StopIteration.

Например, это никогда не останавливается: (ПЕРЕСМОТРЕНО)

from random import randint
def devtrue():
    while True:
        yield True

answers=[False for _ in range(randint(100,100000))]
answers[::randint(3,19)]=devtrue()
print answers

Я нашел этот код, но пока не понимаю, какпримените его в этом случае: http://code.activestate.com/recipes/576585-lazy-recursive-generator-function/

Ответы [ 4 ]

8 голосов
/ 24 июля 2010

Вы можете вызвать close() на объекте генератора. Таким образом, в генераторе возникает исключение GeneratorExit, и дальнейшие вызовы его метода next() вызовут StopIteration:

>>> def test():
...     while True:
...         yield True
... 
>>> gen = test()
>>> gen
<generator object test at ...>
>>> gen.next()
True
>>> gen.close()
>>> gen.next()
Traceback (most recent call last):
  ...
StopIteration
0 голосов
/ 25 июля 2010

По аналогии с функцией take в Haskell, вы можете построить «ограниченный» генератор на основе другого генератора:

def take(n,gen):
    '''borrowed concept from functional languages'''
togo=n
while togo > 0:
    yield gen.next()
    togo = togo - 1

def naturalnumbers():
    ''' an unlimited series of numbers '''
    i=0
    while True:
        yield i
        i=i+1

for n in take(10, naturalnumbers() ):
   print n

Вы можете продвинуть эту идею с помощью генератора "while", "while", ...

def gen_until( condition, gen ):
   g=gen.next()
   while( not condition(g) ):
      yield g
      g=gen.next()

И используйте это как

for i in gen_until( lambda x: x*x>100, naturalnumbers() ):
  print i

...

0 голосов
/ 25 июля 2010

Это лучшее, что я придумал, но он все равно выполняет нарезку дважды, чтобы найти длину и нужно преобразовать номер строки из разбиения в int:

from time import clock
from random import randint
a=[True for _ in range(randint(1000000,10000000))]
spacing=randint(3,101)
t=clock()
try:
    a[::spacing]=[False]
except ValueError as e:
    a[::spacing]=[False]*int(e.message.rsplit(' ',1)[-1])

print spacing,clock()-t

# baseline

t=clock()
a[::spacing]=[False]*len(a[::spacing])
print 'Baseline:',spacing,clock()-t

Я попытаюсь сделать это на своем простом сите, но, скорее всего, это будет не быстрее, чем выполнение арифметики длины по формуле повторения. Улучшение чистого сита Python по формуле повторения

0 голосов
/ 24 июля 2010

Как вы уже видели,

TypeError: 'generator' object is unsubscriptable

И как вы написали devtrue, это не должно прекратиться.Если вам нужна эта мощность, вы можете:

def bounded_true(count)
   while count > 0:
       yield True
       count -= 1

или, что гораздо проще:

y = [True] * 5

Если вы создадите бесконечный генератор, он будет генерировать бесконечно.

...