2010-07-24 20 views
3

Y a-t-il moyen d'arrêter de céder lorsque le générateur n'a pas fini les valeurs et que tous les résultats nécessaires ont été lus? Je veux dire que ce générateur donne des valeurs sans jamais faire StopIteration.Rendement jusqu'à ce que toutes les valeurs nécessaires soient cédées, est-il possible de faire une tranche pour devenir paresseux

Par exemple, cela ne cesse jamais: (RÉVISÉ)

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 

J'ai trouvé ce code, mais ne comprends pas encore, comment l'appliquer dans ce cas: http://code.activestate.com/recipes/576585-lazy-recursive-generator-function/

Répondre

0

Il est préférable que je suis venu avec, mais il fait encore le découpage deux fois pour trouver la longueur et le besoin de convertir le numéro de chaîne de division 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 

Je vais essayer à mon tamis premier, mais il est probable qu'il ne soit pas plus rapide que de faire l'arithmétique de la longueur à partir de la formule de récurrence. Improving pure Python prime sieve by recurrence formula

8

Vous pouvez appeler close() sur l'objet générateur. De cette façon, une exception GeneratorExit est soulevée dans le générateur et d'autres appels à sa méthode next() soulèvera 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

Comme vous l'avez déjà vu,

TypeError: 'generator' object is unsubscriptable 

Et la façon dont vous avez écrit devtrue il ne devrait pas arrêter. Si vous avez besoin cette capacité, vous pouvez:

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

ou bien plus simplement:

y = [True] * 5 

Si vous faites un générateur infini, il va générer à l'infini.

+0

Cela ne devrait pas être impossible, voir par exemple/dev/random pseudofile. Peut-être avons-nous besoin d'un package generatorIO en plus de stringIO? –

+0

Ce n'est pas impossible. Vous avez écrit un générateur infini et obtenu ce que vous avez demandé. Je vous ai donné un exemple que je viens de simplifier pour plus de clarté. – msw

+0

Le problème n'est pas le générateur, ce que je voulais: le générateur donnant toujours la même valeur. Je voudrais seulement que la tranche agisse comme itérateur (la liste est itérable tu sais) et fait le StopIteration à la fin de la tranche. –

0

Par analogie avec la fonction take dans Haskell, vous pouvez construire un générateur « limité » sur la base d'un autre générateur:

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 

Vous pouvez poursuivre cette idée avec un « jusqu'à ce que » générateur, un « tout » ...

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

Et l'utiliser comme

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

...

+0

Pourquoi utiliser une prise autodéfinie au lieu d'islice? Pour moi, l'incrément général est suffisant, les nombres naturels sont des cas spéciaux avec la valeur de départ 0. Serait intéressant si les générateurs auraient accès à la valeur précédente générée sans avoir besoin de définir explicitement la variable avec la valeur de résultat . –

+0

@Tony Veijalainen: J'ai probablement mal interprété votre question. Je pensais que vous aviez besoin d'un moyen de limiter le nombre de résultats obtenus, indépendamment de l'arrêt explicite du générateur. En plus de cela, je n'ai pas encore atteint une bonne connaissance des outils. Merci d'avoir fait remarquer cela! – xtofl

+0

Vous pouvez peut-être m'apprendre un truc ou deux si vous avez de l'expérience à Haskell. –