2015-04-10 25 views
21

Quindi ho una funzione di generatore, che assomiglia a questo.Generatori e loop in Python

def generator(): 
    while True: 
     for x in range(3): 
      for j in range(5): 
       yield x 

Quando si carica su questa funzione e lo chiamo "next" un mucchio di volte, mi aspetto che producesse valori

0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 0 0 0 0 0 ...

Ma invece solo i rendimenti 0 per tutto il tempo. Perché?

>>> execfile("test.py") 
>>> generator 
<function generator at 0x10b6121b8> 
>>> generator().next() 
0 
>>> generator().next() 
0 
>>> generator().next() 
0 
>>> generator().next() 
0 
>>> generator().next() 
0 
>>> generator().next() 
0 
>>> generator().next() 
0 
+24

Non riesco a capire perché questo è così speciale. Se riacquistassi qualche lezione, nessuno sarebbe sorpreso quando qualche tipo di valore iniziale non viene aggiornato! Per esempio. caricare 10 volte in un file e fare 'next()' e 'print' non sarebbe così spettacolare da richiedere 14 upvotes e 2 preferiti ... – PascalVKooten

+3

Risposta breve, ogni chiamata' generator() 'restituisce un nuovo oggetto generatore che inizia al suo inizio Prova 'gen = generator()', quindi 'gen.next()', 'gen.next()', ecc. – martineau

risposta

48

generator() inizializza nuovo oggetto generatore:

In [4]: generator() is generator() # Creating 2 separate objects 
Out[4]: False 

Poi generator().next() ottiene il primo valore dall'oggetto generatore appena creato (nel tuo caso).

Si dovrebbe chiamare generator una volta:

In [5]: gen = generator() # Storing new generator object, will reuse it 

In [6]: [gen.next() for _ in range(6)] # Get first 6 values for demonstration purposes 
Out[6]: [0, 0, 0, 0, 0, 1] 

Nota: generator.next è stato rimosso da Python 3 (PEP 3114) - utilizzare il next function invece:

In [7]: next(gen) 
Out[7]: 1 
+4

.. ma 'generatore .__ next__' è stato aggiunto. Comunque, dovresti comunque usare la funzione 'next()'. –

17

Con ogni chiamata di generator sei creazione di un nuovo oggetto generatore:

generator().next() # 1st item in 1st generator 
generator().next() # 1st item in 2nd generator 

Creare un generatore, e quindi chiamare il next per gli elementi successivi:

g = generator() 

g.next() # 1st item in 1st generator 
g.next() # 2nd item in 1st generator 
+1

Un nuovo generatore ** oggetto **, sicuramente? – immibis

+0

@immibis Ci scusiamo, terminologia corretta. –

2

ho postato nel commento, penso che se si guarda a questo in parallelo con la domanda che si vede l'errore:

with open('my_file.txt', 'r') as f: 
    print(f.readline())    # `readline` simply reads a single line 

with open('my_file.txt', 'r') as f: 
    print(f.readline()) 

with open('my_file.txt', 'r') as f: 
    print(f.readline()) 

with open('my_file.txt', 'r') as f: 
    print(f.readline())  

Invece di fare un nuovo generatore oggetto ogni volta, si deve fare una volta e poi utilizzarlo finché non è stato impoverito:

mygen = generator() 
mygen.next() 
mygen.next() 
... 
etc