DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on • Edited on

Iterator in Python (3)

Buy Me a Coffee

*Memos:

A generator:

  • is the function with one or more yield statements. *A yield statement is a yield or yield 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 a yield or yield 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:
Enter fullscreen mode Exit fullscreen mode

<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:
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

<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: 
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

<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:
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode
def func():
    yield 'a'
    yield 'b'
    yield 'c'

gen = func()

print(next(gen)) # a

gen.close()

print(next(gen)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode
def func():
    yield 'a'
    yield 'b'
    yield 'c'

gen = func()

print(next(gen)) # a
print(next(gen)) # b

gen.close()

print(next(gen)) # StopIteration:
Enter fullscreen mode Exit fullscreen mode

*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()
Enter fullscreen mode Exit fullscreen mode

A generator's iterator cannot be copied as shown below:

*Memos:

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
Enter fullscreen mode Exit fullscreen mode

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