2012-10-26 8 views
42

Być może padłem ofiarą dezinformacji w Internecie, ale wydaje mi się, że jest to bardziej prawdopodobne, że coś źle zrozumiałem. Na podstawie tego, czego się nauczyłem do tej pory, range() jest generatorem, a generatory mogą być używane jako iteratory. Jednak ten kod:Jeśli range() jest generatorem w Pythonie 3.3, dlaczego nie mogę wywołać next() w zakresie?

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

daje mi ten błąd:

TypeError: 'range' object is not an iterator 

Co ja tu brakuje? Spodziewałem się, że wydrukuję 0 i przejdę do następnej wartości w myrange. Jestem nowy w Pythonie, więc proszę przyjąć moje przeprosiny za raczej podstawowe pytanie, ale nigdzie indziej nie znalazłem dobrego wyjaśnienia.

+1

Zobacz http://stackoverflow.com/q/13054057/395760 dla rozróżnienia iteratory i rzeczy, które można iterować w 'for' pętli. – delnan

+0

Czy to słuszne, aby powiedzieć, że generatory są iterable, ale nie iteratory? – Jeff

+1

@Jeff Iterables to obiekty, których 'iter' może być użyty do uzyskania iteratora. Iteratory są obiektami, które mogą być iterowane przy użyciu 'next'. Generatory to kategoria iteratorów (funkcje generatora i wyrażeń generatora). Przynajmniej tak myślę ... –

Odpowiedz

50

range to klasa niezmiennych obiektów iteracyjnych. Ich zachowanie iteracyjne można porównać do list s: nie można wywołać bezpośrednio na nich next; musisz pobrać iterator za pomocą iter.

Więc nie, range nie jest generatorem.

Być może myślisz: "dlaczego nie zrobili tego bezpośrednio"? Cóż, range s ma kilka przydatnych właściwości, które nie byłyby możliwe w ten sposób:

  • Są one niezmienne, więc mogą być używane jako klucze słownika.
  • Mają start, stop i step atrybuty (od Pythona 3.3) count i index metod i wspierają in, len i __getitem__ operacje.
  • Możesz wielokrotnie powtórzyć ten sam numer 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

Inną fajną cechą obiektów 'range' jest to, że mają metodę' _contain__', która może być użyta do sprawdzenia, czy wartość znajduje się w zakresie: '5 w zakresie (10) => Prawda " – kindall

+0

Dzięki za odpowiedź; teraz ma to sens. Jedyną rzeczą, którą chcę wyjaśnić przed zaakceptowaniem twojej odpowiedzi, jest notatka zaznaczona kursywą o jedną trzecią strony w dół [to] (http://wiki.python.org/moin/Generators), która stwierdza, że ​​"w Pythonie 3 zakres() to generator ". Czy to po prostu niepoprawne? – Jeff

+2

@Jeff Ściśle mówiąc, tak, to jest złe. Autor notatki prawdopodobnie oznaczał, że w Pythonie 3 'range' jest * leniwy * (w porównaniu do Pythona 2, gdzie jest to tylko funkcja, która zwraca listę). –