Python Language
Iterabile i Iteratory
Szukaj…
Iterator vs Iterable vs Generator
Iterowalny to obiekt, który może zwrócić iterator . Każdy obiekt ze stanem, który ma metodę __iter__
i zwraca iterator, jest iterowalny. Może to być także obiekt bez stanu, który implementuje metodę __getitem__
. - Metoda może przyjmować indeksy (od zera) i wywoływać błąd IndexError
gdy indeksy nie są już ważne.
Klasa str
Pythona jest przykładem iterowalnego __getitem__
.
Iterator to obiekt, który generuje następną wartość w sekwencji, gdy wywołasz next(*object*)
na jakimś obiekcie. Ponadto każdy obiekt z metodą __next__
jest iteratorem. Iterator podnosi StopIteration
po wyczerpaniu iteratora i w tym momencie nie można go ponownie użyć.
Klasy iterowalne:
Klasy __iter__
definiują metodę __iter__
i __next__
. Przykład klasy iterowalnej:
class MyIterable:
def __iter__(self):
return self
def __next__(self):
#code
#Classic iterable object in older versions of python, __getitem__ is still supported...
class MySequence:
def __getitem__(self, index):
if (condition):
raise IndexError
return (item)
#Can produce a plain `iterator` instance by using iter(MySequence())
Próbuję utworzyć instancję klasy abstrakcyjnej z modułu collections
, aby lepiej to zobaczyć.
Przykład:
import collections
>>> collections.Iterator()
>>> TypeError: Cant instantiate abstract class Iterator with abstract methods next
>>> TypeError: Cant instantiate abstract class Iterator with abstract methods __next__
Obsługuj kompatybilność Python 3 dla iterowalnych klas w Python 2, wykonując następujące czynności:
class MyIterable(object): #or collections.Iterator, which I'd recommend....
....
def __iter__(self):
return self
def next(self): #code
__next__ = next
Oba są teraz iteratorami i można je zapętlać:
ex1 = MyIterableClass()
ex2 = MySequence()
for (item) in (ex1): #code
for (item) in (ex2): #code
Generatory to proste sposoby tworzenia iteratorów. Generator to iterator, a iterator to iterowalny.
Co może być iterowalne
Iterowalny może być dowolny element , dla którego elementy są odbierane jeden po drugim, tylko do przodu . Wbudowane kolekcje Python są iterowalne:
[1, 2, 3] # list, iterate over items
(1, 2, 3) # tuple
{1, 2, 3} # set
{1: 2, 3: 4} # dict, iterate over keys
Generatory zwracają iteracje:
def foo(): # foo isn't iterable yet...
yield 1
res = foo() # ...but res already is
Iteracja po całej iteracji
s = {1, 2, 3}
# get every element in s
for a in s:
print a # prints 1, then 2, then 3
# copy into list
l1 = list(s) # l1 = [1, 2, 3]
# use list comprehension
l2 = [a * 2 for a in s if a > 2] # l2 = [6]
Sprawdź tylko jeden element w iterowalnym
Użyj rozpakowywania, aby wyodrębnić pierwszy element i upewnij się, że jest on jedyny:
a, = iterable
def foo():
yield 1
a, = foo() # a = 1
nums = [1, 2, 3]
a, = nums # ValueError: too many values to unpack
Wyodrębnij wartości jeden po drugim
Rozpocznij z wbudowanym iter()
aby uzyskać iterator nad iterowalnością, i użyj next()
aby pobrać elementy jeden po drugim, aż StopIteration
zostanie podniesiony, co oznacza koniec:
s = {1, 2} # or list or generator or even iterator
i = iter(s) # get iterator
a = next(i) # a = 1
b = next(i) # b = 2
c = next(i) # raises StopIteration
Iterator nie jest ponownie związany!
def gen():
yield 1
iterable = gen()
for a in iterable:
print a
# What was the first item of iterable? No way to get it now.
# Only to get a new iterator
gen()