*Memos:
- My post explains an iterator (1).
- My post explains an iterator (2).
- My post explains a class-based iterator with __iter__() and/or __next__().
- My post explains itertools about count(), cycle() and repeat().
- My post explains itertools about accumulate(), batched(), chain() and chain.from_iterable().
- My post explains itertools about compress(), filterfalse(), takewhile() and dropwhile().
- My post explains itertools about groupby() and islice().
- My post explains itertools about pairwise(), starmap(), tee() and zip_longest().
- My post explains itertools about product() and permutations().
A generator:
- is the function with one or more
yield
statements. *Ayield
statement is ayield
oryield from
. - can return an iterator.
- 's iterator can be create by a generator comprehension.
- terminates if there is no value to return, if close() is called or of course if error occurs.
- 's iterator cannot be copied.
You can create a generator with a function and one or more yield
statements and access it with next()
as shown below:
*Memos:
- A
yield
statements is ayield
oryield from
. - A
yield
can return any types of a value. - A
yield from
can only return an iterable.
<yield
>
def func():
yield 'a'
yield 'b'
yield 'c'
print(func) # <function func at 0x000001FCD2FF93A0>
print(type(func)) # <class 'function'>
gen = func()
print(gen) # <generator object func at 0x000001FCD3015220>
print(type(gen)) # <class 'generator'>
print(next(gen)) # a
print(next(gen)) # b
print(next(gen)) # c
print(next(gen)) # StopIteration:
<yield from
>
def func():
yield from ['a', 'b', 'c']
yield from ['d', 'e', 'f']
print(func) # <function func at 0x000001FCD640B1A0>
print(type(func)) # <class 'function'>
gen = func()
print(gen) # <generator object func at 0x000001FCD661DD80>
print(type(gen)) # <class 'generator'>
print(next(gen)) # a
print(next(gen)) # b
print(next(gen)) # c
print(next(gen)) # d
print(next(gen)) # e
print(next(gen)) # f
print(next(gen)) # StopIteration:
This is how a generator works as shown below:
<yield
>
def func():
print("func() starts.")
yield "func() pauses."
print("func() resumes.")
yield "func() pauses again."
print("func() resumes again.")
yield "func() terminates."
gen = func() # `func()` doesn't start yet.
print(next(gen))
# func() starts.
# func() pauses.
print(next(gen))
# func() resumes.
# func() pauses again.
print(next(gen))
# func() resumes again.
# func() terminates.
print(next(gen)) # StopIteration:
<yield from
>
def func():
print("func() starts.")
yield from ["func() pauses.",
"func() resumes and pauses."]
print("func() resumes.")
yield from ["func() pauses.",
"func() resumes and terminates."]
gen = func() # `func()` doesn't start yet.
print(next(gen))
# func() starts.
# func() pauses.
print(next(gen))
# func() resumes and pauses.
print(next(gen))
# func() resumes.
# func() pauses.
print(next(gen))
# func() resumes and terminates.
print(next(gen)) # StopIteration:
This is the generator with a for
statement as shown below:
<yield
>
def func():
for x in ['a', 'b', 'c']:
yield x
gen = func()
print(next(gen)) # a
print(next(gen)) # b
print(next(gen)) # c
print(next(gen)) # StopIteration:
<yield from
>
def func():
for x in [['a', 'b', 'c'], ['d', 'e', 'f']]:
yield from x
gen = func()
print(next(gen)) # a
print(next(gen)) # b
print(next(gen)) # c
print(next(gen)) # d
print(next(gen)) # e
print(next(gen)) # f
print(next(gen)) # StopIteration:
A generator comprehension can create a generator's iterator as shown below:
gen = (x.upper() for x in ['a', 'b', 'c'])
print(gen) # <generator object <genexpr> at 0x00000168B98E9080>
print(type(gen)) # <class 'generator'>
print(next(gen)) # A
print(next(gen)) # B
print(next(gen)) # C
close() can terminate a generator as shown below. *There are no arguments:
def func():
yield 'a'
yield 'b'
yield 'c'
gen = func()
gen.close()
print(next(gen)) # StopIteration:
def func():
yield 'a'
yield 'b'
yield 'c'
gen = func()
print(next(gen)) # a
gen.close()
print(next(gen)) # StopIteration:
def func():
yield 'a'
yield 'b'
yield 'c'
gen = func()
print(next(gen)) # a
print(next(gen)) # b
gen.close()
print(next(gen)) # StopIteration:
*close()
should be used in a finally
clause to terminate a generator for when error occurs.
def func():
yield 'a'
yield 'b'
yield 'c'
gen = func()
try:
print(next(gen)) # a
print(next(gen)) # b
print(next(gen)) # c
finally:
gen.close()
A generator's iterator cannot be copied as shown below:
*Memos:
- copy() can do shallow copy.
- deepcopy() can do deep copy.
from copy import copy
from copy import deepcopy
def func():
yield 'a'
yield 'b'
yield 'c'
v1 = func()
v2 = copy(v1)
v2 = deepcopy(v1)
# TypeError: cannot pickle 'generator' object
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more