Różnica między generatorami Python a iteratorami


Odpowiedzi:


542

iteratorjest bardziej ogólną koncepcją: każdy obiekt, którego klasa ma nextmetodę ( __next__w Pythonie 3) i __iter__metodę, która ją posiada return self.

Każdy generator jest iteratorem, ale nie odwrotnie. Generator jest zbudowany przez wywołanie funkcji, która ma jedno lub więcej yieldwyrażeń ( yieldinstrukcji w Pythonie 2.5 i wcześniejszych) i jest obiektem spełniającym definicję an z poprzedniego akapitu iterator.

Możesz użyć niestandardowego iteratora zamiast generatora, gdy potrzebujesz klasy o nieco złożonym zachowaniu utrzymującym stan lub chcesz ujawnić inne metody oprócz next( __iter__i __init__). Najczęściej generator (czasami, dla wystarczająco prostych potrzeb, wyrażenie generatora ) jest wystarczający i jest łatwiejszy do kodowania, ponieważ utrzymanie stanu (w rozsądnych granicach) jest w zasadzie „wykonywane dla ciebie” przez zawieszenie i wznowienie ramki.

Na przykład generator, taki jak:

def squares(start, stop):
    for i in range(start, stop):
        yield i * i

generator = squares(a, b)

lub równoważne wyrażenie generatora (genexp)

generator = (i*i for i in range(a, b))

zajęłoby więcej kodu do zbudowania jako niestandardowy iterator:

class Squares(object):
    def __init__(self, start, stop):
       self.start = start
       self.stop = stop
    def __iter__(self): return self
    def next(self): # __next__ in Python 3
       if self.start >= self.stop:
           raise StopIteration
       current = self.start * self.start
       self.start += 1
       return current

iterator = Squares(a, b)

Ale oczywiście z klasą Squaresmożna łatwo zaoferować dodatkowe metody, tj

    def current(self):
       return self.start

jeśli rzeczywiście potrzebujesz takiej dodatkowej funkcjonalności w swojej aplikacji.


jak korzystać z iteratora po jego utworzeniu?
Vincenzooo

@Vincenzooo, które zależy od tego, co chcesz z tym zrobić. Będzie to albo część for ... in ...:, albo funkcja, albo zadzwonisziter.next()
Caleth

@Caleth Pytałem o dokładną składnię, ponieważ dostałem błąd przy próbie użycia tej for..inskładni. Może czegoś mi brakowało, ale to było jakiś czas temu, nie pamiętam, czy rozwiązałem. Dziękuję Ci!
Vincenzooo

135

Jaka jest różnica między iteratorami a generatorami? Przydałoby się kilka przykładów użycia każdego przypadku.

Podsumowując: Iteratory to obiekty, które mają metodę __iter__i __next__( nextw Pythonie 2). Generatory zapewniają łatwy, wbudowany sposób tworzenia instancji Iteratorów.

Funkcja z wydajnością jest nadal funkcją, która po wywołaniu zwraca instancję obiektu generatora:

def a_function():
    "when called, returns generator object"
    yield

Wyrażenie generatora zwraca również generator:

a_generator = (i for i in range(0))

Aby uzyskać bardziej szczegółową ekspozycję i przykłady, czytaj dalej.

Generator to iterator

W szczególności generator jest podtypem iteratora.

>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True

Generator możemy stworzyć na kilka sposobów. Bardzo powszechnym i prostym sposobem na to jest funkcja.

W szczególności funkcja z wydajnością jest funkcją, która po wywołaniu zwraca generator:

>>> def a_function():
        "just a function definition with yield in it"
        yield
>>> type(a_function)
<class 'function'>
>>> a_generator = a_function()  # when called
>>> type(a_generator)           # returns a generator
<class 'generator'>

Generator znowu jest iteratorem:

>>> isinstance(a_generator, collections.Iterator)
True

Iterator to Iterable

Iterator to Iterable,

>>> issubclass(collections.Iterator, collections.Iterable)
True

co wymaga __iter__metody zwracającej Iterator:

>>> collections.Iterable()
Traceback (most recent call last):
  File "<pyshell#79>", line 1, in <module>
    collections.Iterable()
TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__

Niektóre przykłady iterable to wbudowane krotki, listy, słowniki, zestawy, zestawy zamrożone, ciągi, ciągi bajtów, tablice bajtów, zakresy i widoki pamięci:

>>> all(isinstance(element, collections.Iterable) for element in (
        (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

Iterators wymagająnext lub __next__metody

W Python 2:

>>> collections.Iterator()
Traceback (most recent call last):
  File "<pyshell#80>", line 1, in <module>
    collections.Iterator()
TypeError: Can't instantiate abstract class Iterator with abstract methods next

A w Python 3:

>>> collections.Iterator()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Iterator with abstract methods __next__

Możemy pobrać iteratory z wbudowanych obiektów (lub obiektów niestandardowych) za pomocą iterfunkcji:

>>> all(isinstance(iter(element), collections.Iterator) for element in (
        (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

__iter__Metoda jest wywoływana, gdy spróbujesz użyć obiektu w pętli for. Następnie __next__metoda jest wywoływana na obiekcie iteratora w celu pobrania każdego elementu do pętli. Iterator podnosi się, StopIterationgdy go wyczerpałeś i nie można go ponownie użyć w tym momencie.

Z dokumentacji

Z sekcji Typy generatorów w sekcji Typy iteratorów w dokumentacji Typów wbudowanych :

Generatory Pythona zapewniają wygodny sposób implementacji protokołu iteratora. Jeśli __iter__()metoda obiektu kontenerowego zostanie zaimplementowana jako generator, automatycznie zwróci obiekt iteratora (technicznie rzecz biorąc, obiekt generatora) dostarczający metody __iter__()i next()[ __next__()w Pythonie 3]. Więcej informacji na temat generatorów można znaleźć w dokumentacji wyrażenia wydajności.

(Podkreślenie dodane.)

Z tego dowiadujemy się, że Generatory to (wygodny) typ Iteratora.

Przykładowe obiekty iteratora

Możesz utworzyć obiekt, który implementuje protokół Iterator, tworząc lub rozszerzając własny obiekt.

class Yes(collections.Iterator):

    def __init__(self, stop):
        self.x = 0
        self.stop = stop

    def __iter__(self):
        return self

    def next(self):
        if self.x < self.stop:
            self.x += 1
            return 'yes'
        else:
            # Iterators must raise when done, else considered broken
            raise StopIteration

    __next__ = next # Python 3 compatibility

Ale łatwiej jest po prostu użyć Generatora, aby to zrobić:

def yes(stop):
    for _ in range(stop):
        yield 'yes'

Lub może prościej, Wyrażenie Generatora (działa podobnie do wyrażeń listowych):

yes_expr = ('yes' for _ in range(stop))

Wszystkie mogą być używane w ten sam sposób:

>>> stop = 4             
>>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop), 
                             ('yes' for _ in range(stop))):
...     print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3))
...     
0: yes == yes == yes
1: yes == yes == yes
2: yes == yes == yes
3: yes == yes == yes

Wniosek

Możesz użyć protokołu Iterator bezpośrednio, gdy potrzebujesz rozszerzyć obiekt Python jako obiekt, który można iterować.

Jednak w zdecydowanej większości przypadków najlepiej jest użyć yielddo zdefiniowania funkcji, która zwraca Iterator Generatora lub rozważenia Wyrażeń Generatora.

Na koniec zauważ, że generatory zapewniają jeszcze większą funkcjonalność jako coroutines. Wyjaśniam Generatory wraz ze yieldstwierdzeniem dogłębnie w mojej odpowiedzi na „Co robi słowo kluczowe„ wydajność ”?”.


41

Iteratory:

Iterator to obiekty, które wykorzystują next()metodę do uzyskania następnej wartości sekwencji.

Generatory:

Generator to funkcja, która generuje lub generuje sekwencję wartości przy użyciu yield metody.

Każde next()wywołanie metody na obiekcie generatora (np. fJak w poniższym przykładzie) zwrócone przez funkcję generatora (na przykład: foo()funkcja w poniższym przykładzie), generuje kolejną wartość w sekwencji.

Wywołanie funkcji generatora powoduje zwrócenie obiektu generatora nawet bez rozpoczęcia wykonywania funkcji. Gdy next()metoda jest wywoływana po raz pierwszy, funkcja rozpoczyna wykonywanie, dopóki nie osiągnie instrukcji dochodu, która zwraca uzyskaną wartość. Wydajność śledzi np. Pamięta ostatnie wykonanie. Drugie next()połączenie jest kontynuowane od poprzedniej wartości.

Poniższy przykład pokazuje wzajemne oddziaływanie między wydajnością a wywołaniem kolejnej metody na obiekcie generatora.

>>> def foo():
...     print "begin"
...     for i in range(3):
...         print "before yield", i
...         yield i
...         print "after yield", i
...     print "end"
...
>>> f = foo()
>>> f.next()
begin
before yield 0            # Control is in for loop
0
>>> f.next()
after yield 0             
before yield 1            # Continue for loop
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

3
Po prostu FYI nie jest metodą, to słowo kluczowe
Jay Parikh

25

Dodanie odpowiedzi, ponieważ żadna z istniejących odpowiedzi nie odnosi się konkretnie do zamieszania w oficjalnej literaturze.

Funkcje generatora to zwykłe funkcje zdefiniowane za pomocąyieldzamiastreturn. Po wywołaniu funkcja generatora zwraca obiekt generatora , który jest rodzajem iteratora - manext()metodę. Po wywołaniunext()zwracana jest następna wartość uzyskana przez funkcję generatora.

Zarówno funkcja, jak i obiekt mogą być nazywane „generatorem” w zależności od tego, który dokument źródłowy w Pythonie czytasz. Python słowniczek mówi funkcji generatora, podczas gdy Python wiki implikuje obiekty generatora. Samouczek Python wybitnie zarządza się sugerować zarówno widma w przestrzeni trzech zdaniach:

Generatory to proste i wydajne narzędzie do tworzenia iteratorów. Są one pisane jak zwykłe funkcje, ale używają instrukcji fed za każdym razem, gdy chcą zwrócić dane. Za każdym razem, gdy wywoływana jest funkcja next (), generator wznawia od miejsca, w którym został przerwany (zapamiętuje wszystkie wartości danych i ostatnią instrukcję).

Pierwsze dwa zdania identyfikują generatory z funkcjami generatora, a trzecie zdanie identyfikuje je z obiektami generatora.

Pomimo całego tego zamieszania, można znaleźć odniesienie do języka Python dla jasnego i końcowego słowa:

Wyrażenie wydajności jest używane tylko podczas definiowania funkcji generatora i może być użyte tylko w treści definicji funkcji. Użycie wyrażenia plonu w definicji funkcji jest wystarczające, aby definicja ta utworzyła funkcję generatora zamiast funkcji normalnej.

Po wywołaniu funkcji generatora zwraca iterator zwany generatorem. Ten generator kontroluje następnie wykonywanie funkcji generatora.

Tak więc, w formalnym i precyzyjnym użyciu, „generator” bez zastrzeżeń oznacza obiekt generatora, a nie funkcję generatora.

Powyższe odniesienia dotyczą Python 2, ale odniesienie do języka Python 3 mówi to samo. Jednak glosariusz Python 3 stwierdza, że

generator ... Zwykle odnosi się do funkcji generatora, ale może odnosić się do iteratora generatora w niektórych kontekstach. W przypadkach, gdy zamierzone znaczenie nie jest jasne, użycie pełnych terminów pozwala uniknąć dwuznaczności.


Nie sądzę, aby było wiele zamieszania między funkcjami generatora a obiektami generatora, z tego samego powodu zwykle nie ma zamieszania między klasami i ich instancjami. W obu przypadkach dzwonisz do jednego, aby uzyskać drugi, aw swobodnej rozmowie (lub szybko napisanej dokumentacji) możesz użyć nazwy klasy lub słowa „generator” dla każdego z nich. Musisz tylko wyraźnie powiedzieć o „funkcji generatora” w porównaniu z „obiektem generatora” w rzadkich sytuacjach, o których mówisz.
Blckknght

6
1. Bez względu na teoretyczne powody, dla których nie powinno się wprowadzać zamieszania, komentarze do innych odpowiedzi na to pytanie zaprzeczają sobie i zaprzeczają sobie bez rozwiązania, co wskazuje na faktyczne zamieszanie. 2. Przypadkowa niedokładność jest w porządku, ale dokładne, wiarygodne źródło powinno być przynajmniej jedną z opcji SO. W moim obecnym projekcie intensywnie korzystam zarówno z funkcji generatora, jak i obiektów, a rozróżnienie jest bardzo ważne przy projektowaniu i kodowaniu. Dobrze wiedzieć, jakiej terminologii należy teraz używać, więc nie muszę później zmieniać dziesiątek nazw zmiennych i komentarzy.
Paul

2
Wyobraź sobie literaturę matematyczną, w której nie rozróżnia się funkcji od jej wartości zwracanej. Czasami wygodne jest ich nieformalne połączenie, ale zwiększa to ryzyko popełnienia różnych błędów. Zaawansowana nowoczesna matematyka byłaby znacznie i niepotrzebnie utrudniona, gdyby rozróżnienie nie zostało sformalizowane w konwencji, języku i notacji.
Paul

2
Funkcje wyższego rzędu przenoszące się wokół generatorów lub funkcje generatora mogą zabrzmieć dziwnie, ale dla mnie nadchodzą. Pracuję w Apache Spark, która wymusza bardzo funkcjonalny styl programowania. Funkcje muszą tworzyć, przekazywać i przekazywać różnego rodzaju obiekty, aby wykonać zadanie. Miałem wiele sytuacji, w których straciłem orientację, z jakim „generatorem” pracowałem. Wskazówki w nazwach zmiennych i komentarzach, przy użyciu spójnej i poprawnej terminologii, pomogły wyjaśnić zamieszanie. Niewidoczność jednego Pythona może stanowić centrum projektu innego!
Paul

1
@Paul, dziękuję za napisanie tej odpowiedzi. To zamieszanie jest ważne, ponieważ różnica między obiektem generatora a funkcją generatora jest różnicą między uzyskaniem pożądanego zachowania a koniecznością wyszukiwania generatorów.
blujay,

16

Każdy ma naprawdę miłą i pełną odpowiedzi odpowiedź z przykładami i bardzo to doceniam. Chciałem tylko udzielić krótkiej linijki odpowiedzi dla osób, które wciąż nie są całkiem jasne koncepcyjnie:

Jeśli utworzysz własny iterator, jest to trochę zaangażowane - musisz stworzyć klasę i przynajmniej zaimplementować iter i kolejne metody. Ale co, jeśli nie chcesz przejść przez ten problem i chcesz szybko utworzyć iterator. Na szczęście Python zapewnia skrót do definiowania iteratora. Wszystko, co musisz zrobić, to zdefiniować funkcję z co najmniej 1 wywołaniem, aby uzyskać, a teraz, gdy wywołasz tę funkcję, zwróci „ coś ”, co będzie działać jak iterator (możesz wywołać następną metodę i użyć jej w pętli for). To coś ma w Pythonie nazwę Generator

Mam nadzieję, że to trochę wyjaśnia.


9

Poprzednie odpowiedzi pomijały ten dodatek: generator ma closemetodę, podczas gdy typowe iteratory nie. Ta closemetoda wyzwala StopIterationwyjątek w generatorze, który może zostać przechwycony w finallyklauzuli w tym iteratorze, aby uzyskać szansę na przeprowadzenie czyszczenia. Ta abstrakcja sprawia, że ​​jest najbardziej użyteczna w dużych niż prostych iteratorach. Generator można zamknąć tak, jak można zamknąć plik, bez zawracania sobie głowy tym, co jest pod spodem.

To powiedziawszy, moja osobista odpowiedź na pierwsze pytanie brzmiałaby: iterowalna ma __iter__tylko metodę, typowe iteratory mają __next__tylko metodę, generatory mają zarówno __iter__i, jak __next__i dodatkową close.

W przypadku drugiego pytania moja osobista odpowiedź brzmiałaby: w publicznym interfejsie mam tendencję do faworyzowania generatorów, ponieważ jest on bardziej odporny: closemetoda ma większą kompozycję yield from. Lokalnie mogę używać iteratorów, ale tylko wtedy, gdy jest to płaska i prosta struktura (iteratory nie dają się łatwo komponować) i jeśli istnieją powody, by sądzić, że sekwencja jest raczej krótka, szczególnie jeśli można ją zatrzymać przed osiągnięciem końca. Zwykle patrzę na iteratory jako na prymitywny poziom niski, z wyjątkiem literałów.

W kwestiach związanych z przepływem sterowania generatory są równie ważną koncepcją, jak obietnice: oba są abstrakcyjne i można je komponować.


Czy możesz podać przykład, który zilustrowałeś mówiąc o kompozycji? Czy możesz również wyjaśnić, co masz na myśli, mówiąc o „ typowych iteratorach”?
bli

1
Inna odpowiedź ( stackoverflow.com/a/28353158/1878788 ) stwierdza, że ​​„iterator jest iterowalny”. Skoro iterowalny ma __iter__metodę, to dlaczego iterator może mieć __next__tylko? Gdyby miały to być iterowalne, oczekiwałbym, że również będą musiały __iter__.
bli

1
@bli: AFAICS ta odpowiedź tutaj odnosi się do standardowego PEP234 , więc jest poprawna, podczas gdy druga odpowiedź odnosi się do niektórych implementacji, więc jest wątpliwa. Standard wymaga tylko __iter__iterabeli do zwrócenia iteratora, który wymaga tylko nextmetody ( __next__w Python3). Proszę nie mylić standardów (dotyczących pisania kaczego) z ich implementacją (jak zaimplementował to konkretny interpreter Pythona). To trochę przypomina pomieszanie funkcji generatora (definicja) i obiektów generatora (implementacja). ;)
Tino

7

Funkcja generatora, obiekt generatora, generator:

Funkcja Generatora jest jak zwykła funkcja w Pythonie, ale zawiera jedną lub więcej yieldinstrukcji. Funkcje generatora to świetne narzędzie do tworzenia obiektów Iterator tak łatwo, jak to możliwe. Iterator obiekt returend przez funkcję generatora jest również nazywany obiektem Generator lub generatora .

W tym przykładzie utworzyłem funkcję Generator, która zwraca obiekt Generator <generator object fib at 0x01342480>. Podobnie jak inne iteratory, obiekty Generatora mogą być używane w forpętli lub z wbudowaną funkcją, next()która zwraca następną wartość z generatora.

def fib(max):
    a, b = 0, 1
    for i in range(max):
        yield a
        a, b = b, a + b
print(fib(10))             #<generator object fib at 0x01342480>

for i in fib(10):
    print(i)               # 0 1 1 2 3 5 8 13 21 34


print(next(myfib))         #0
print(next(myfib))         #1
print(next(myfib))         #1
print(next(myfib))         #2

Zatem funkcja generatora jest najprostszym sposobem na utworzenie obiektu Iterator.

Iterator :

Każdy obiekt generatora jest iteratorem, ale nie odwrotnie. Niestandardowy obiekt iteratora można utworzyć, jeśli jego klasa implementuje metodę __iter__i __next__metodę (zwaną także protokołem iteratora).

Jednak o wiele łatwiej jest używać funkcji generatorów do tworzenia iteratorów, ponieważ upraszczają one ich tworzenie, ale niestandardowy Iterator daje większą swobodę i możesz także implementować inne metody zgodnie z własnymi wymaganiami, jak pokazano w poniższym przykładzie.

class Fib:
    def __init__(self,max):
        self.current=0
        self.next=1
        self.max=max
        self.count=0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count>self.max:
            raise StopIteration
        else:
            self.current,self.next=self.next,(self.current+self.next)
            self.count+=1
            return self.next-self.current

    def __str__(self):
        return "Generator object"

itobj=Fib(4)
print(itobj)               #Generator object

for i in Fib(4):  
    print(i)               #0 1 1 2

print(next(itobj))         #0
print(next(itobj))         #1
print(next(itobj))         #1

6

Przykłady z Ned Batchelder wysoce zalecane dla iteratorów i generatorów

Metoda bez generatorów, które robią coś z liczbami parzystymi

def evens(stream):
   them = []
   for n in stream:
      if n % 2 == 0:
         them.append(n)
   return them

podczas korzystania z generatora

def evens(stream):
    for n in stream:
        if n % 2 == 0:
            yield n
  • Nie potrzebujemy żadnej listy ani returnoświadczenia
  • Wydajny dla strumienia o dużej / nieskończonej długości ... po prostu idzie i daje wartość

Wywołanie evensmetody (generator) jest jak zwykle

num = [...]
for n in evens(num):
   do_smth(n)
  • Generator służy również do przerywania podwójnej pętli

Iterator

Książka pełna stron jest iterable , zakładka jest iterator

i ta zakładka nie ma nic innego, jak się przenieść next

litr = iter([1,2,3])
next(litr) ## 1
next(litr) ## 2
next(litr) ## 3
next(litr) ## StopIteration  (Exception) as we got end of the iterator

Aby użyć Generatora ... potrzebujemy funkcji

Aby użyć Iteratora ... potrzebujemy nextiiter

Jak powiedziano:

Funkcja Generator zwraca obiekt iteratora

Cała zaleta Iteratora:

Przechowuj jeden element na raz w pamięci


O twoim pierwszym fragmencie kodu chciałbym wiedzieć, czym jeszcze może być „stream” arg niż lista []?
Iqra.

5

Możesz porównać oba podejścia dla tych samych danych:

def myGeneratorList(n):
    for i in range(n):
        yield i

def myIterableList(n):
    ll = n*[None]
    for i in range(n):
        ll[i] = i
    return ll

# Same values
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)
for i1, i2 in zip(ll1, ll2):
    print("{} {}".format(i1, i2))

# Generator can only be read once
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

# Generator can be read several times if converted into iterable
ll1 = list(myGeneratorList(10))
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

Poza tym, jeśli sprawdzisz powierzchnię pamięci, generator zajmie znacznie mniej pamięci, ponieważ nie musi jednocześnie przechowywać wszystkich wartości w pamięci.


1

Piszę specjalnie dla początkujących w Pythonie w bardzo prosty sposób, choć w głębi duszy Python robi tak wiele rzeczy.

Zacznijmy od bardzo podstawowego:

Rozważ listę,

l = [1,2,3]

Napiszmy równoważną funkcję:

def f():
    return [1,2,3]

o / p z print(l): [1,2,3]& o / p zprint(f()) : [1,2,3]

Zróbmy listę l iterowalną: Na liście python jest zawsze iterowalna, co oznacza, że ​​możesz zastosować iterator, kiedy chcesz.

Zastosujmy iterator na liście:

iter_l = iter(l) # iterator applied explicitly

Stwórzmy iterowalną funkcję, tj. Napisz równoważną funkcję generatora. W python, jak tylko wprowadzisz słowo kluczowe yield; staje się funkcją generatora i iterator zostanie zastosowany niejawnie.

Uwaga: Każdy generator jest zawsze iterowalny z zastosowanym niejawnym iteratorem, a tutaj ukryty iterator jest najważniejszy. Więc funkcja generatora będzie:

def f():
  yield 1 
  yield 2
  yield 3

iter_f = f() # which is iter(f) as iterator is already applied implicitly

Więc jeśli zauważyłeś, jak tylko utworzyłeś funkcję generatora fa, jest już iteracyjny (f)

Teraz,

l jest listą, po zastosowaniu metody iteracyjnej „iter” staje się iter (l)

f jest już iter (f), po zastosowaniu metody iteratora „iter” staje się iter (iter (f)), który ponownie jest iter (f)

Trochę rzucasz int na int (x), który już jest int i pozostanie int (x).

Na przykład o / p:

print(type(iter(iter(l))))

jest

<class 'list_iterator'>

Nigdy nie zapominaj, że jest to Python, a nie C lub C ++

Stąd wniosek z powyższego wyjaśnienia jest następujący:

lista l ~ = iter (l)

funkcja generatora f == iter (f)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.