2012-10-26 12 views
42

Forse sono caduto vittima di disinformazione sul web, ma penso che sia più probabile che abbia frainteso qualcosa. Basato su ciò che ho imparato finora, range() è un generatore e i generatori possono essere utilizzati come iteratori. Tuttavia, questo codice:Se range() è un generatore in Python 3.3, perché non posso chiamare next() su un intervallo?

myrange = range(10) 
print(next(myrange)) 

mi dà questo errore:

TypeError: 'range' object is not an iterator 

Che cosa mi manca qui? Mi aspettavo che questo stampasse 0 e per passare al valore successivo in myrange. Sono nuovo di Python, quindi per favore accetta le mie scuse per la domanda piuttosto semplice, ma non ho trovato una buona spiegazione altrove.

+1

Vedere http://stackoverflow.com/q/13054057/395760 per la distinzione tra iteratori e le cose che si possono iterare su in un 'ciclo for'. – delnan

+0

Sarebbe corretto dire che i generatori sono iterabili, ma non iteratori? – Jeff

+1

@Jeff Iterables sono oggetti su cui è possibile utilizzare 'iter' per ottenere un iteratore. Gli iteratori sono oggetti che possono essere ripetuti usando 'next'. I generatori sono una categoria di iteratori (funzioni generatore ed espressioni generatore). Almeno questo è quello che penso ... –

risposta

50

range è una classe di oggetti iterabili immutabili. Il loro comportamento di iterazione può essere paragonato a list s: non è possibile chiamare direttamente next; devi ottenere un iteratore usando iter.

Quindi no, range non è un generatore.

Si potrebbe pensare, "perché non lo rendono direttamente iterabile"? Beh, range s hanno alcune proprietà utili che non sarebbe possibile in questo modo:

  • Essi sono immutabili, in modo che possano essere utilizzati come chiavi di dizionario.
  • hanno gli attributi start, stop e step (dal Python 3.3), count e index metodi e supportano in, len e __getitem__ operazioni.
  • È possibile scorrere più volte lo stesso range.

>>> myrange = range(1, 21, 2) 
>>> myrange.start 
1 
>>> myrange.step 
2 
>>> myrange.index(17) 
8 
>>> myrange.index(18) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: 18 is not in range 
>>> it = iter(myrange) 
>>> it 
<range_iterator object at 0x7f504a9be960> 
>>> next(it) 
1 
>>> next(it) 
3 
>>> next(it) 
5 
+4

Un'altra caratteristica interessante di oggetti 'range' è che hanno un metodo' __contains__' che può essere utilizzato per verificare se un valore è in un intervallo: '5 nella gamma (10) => True' – kindall

+0

Grazie per la risposta; questo ha senso ora. L'unica cosa che voglio chiarire prima di accettare la tua risposta è la nota in corsivo su un terzo della pagina verso il basso [this] (http://wiki.python.org/moin/Generators), che afferma che "in Python 3 range() è un generatore ". È semplicemente sbagliato? – Jeff

+2

@Jeff A rigor di termini, sì, è sbagliato. L'autore della nota probabilmente voleva dire che in Python 3 'range' è * lazy * (rispetto a Python 2 dove è solo una funzione che restituisce una lista). –

Problemi correlati