This content originally appeared on DEV Community and was authored by Super Kai (Kazuya Ito)
*Memo:
- My post explains an iterator (1).
- My post explains an iterator (2).
- My post explains an iterator (3).
- My post explains an iterator (4).
- My post explains a class-based iterator with __iter__() and/or __next__().
- My post explains a generator comprehension.
gi_yieldfrom can return an iterator if the generator is resumed at yield from otherwise it returns None as shown below:
def func():
yield from [0, 1]
yield 2
yield from [3, 4]
yield 5
gen = func()
while True:
try:
print(gen.gi_yieldfrom, next(gen.gi_yieldfrom))
except:
print(gen.gi_yieldfrom, next(gen))
# None 0
# <list_iterator object at 0x000001C66EBFE410> 1
# <list_iterator object at 0x000001C66EBFE410> 2
# None 3
# <list_iterator object at 0x000001C66EBFE410> 4
# <list_iterator object at 0x000001C66EBFE410> 5
gi_running can check if the generator is currently running as shown below:
<yield>:
def func():
print(gen.gi_running, "func") # True func
yield 0
print(gen.gi_running, "func") # True func
yield 1
print(gen.gi_running, "func") # True func
yield 2
print(gen.gi_running, "func") # True func
gen = func()
print(gen.gi_running) # False
print(next(gen)) # 0
print(gen.gi_running) # False
print(next(gen)) # 1
print(gen.gi_running) # False
print(next(gen)) # 2
print(gen.gi_running) # False
print(next(gen)) # StopIteration:
<yield from>:
def func():
print(gen.gi_running, "func") # True func
yield from [0, 1]
print(gen.gi_running, "func") # True func
yield from [2, 3]
print(gen.gi_running, "func") # True func
yield from [4, 5]
print(gen.gi_running, "func") # True func
gen = func()
print(gen.gi_running) # False
print(next(gen)) # 0
print(gen.gi_running) # False
print(next(gen)) # 1
print(gen.gi_running) # False
print(next(gen)) # 2
print(gen.gi_running) # False
print(next(gen)) # 3
print(gen.gi_running) # False
print(next(gen)) # 4
print(gen.gi_running) # False
print(next(gen)) # 5
print(gen.gi_running) # False
print(next(gen)) # StopIteration:
gi_suspended can check if the generator is currently suspended(paused) as shown below:
<yield>:
def func():
print(gen.gi_suspended, "func") # False func
yield 0
print(gen.gi_suspended, "func") # False func
yield 1
print(gen.gi_suspended, "func") # False func
yield 2
print(gen.gi_suspended, "func") # False func
gen = func()
print(gen.gi_suspended) # False
print(next(gen)) # 0
print(gen.gi_suspended) # True
print(next(gen)) # 1
print(gen.gi_suspended) # True
print(next(gen)) # 2
print(gen.gi_suspended) # True
print(next(gen)) # StopIteration:
<yield from>:
def func():
print(gen.gi_suspended, "func") # False func
yield from [0, 1]
print(gen.gi_suspended, "func") # False func
yield from [2, 3]
print(gen.gi_suspended, "func") # False func
yield from [4, 5]
print(gen.gi_suspended, "func") # False func
gen = func()
print(gen.gi_suspended) # False
print(next(gen)) # 0
print(gen.gi_suspended) # True
print(next(gen)) # 1
print(gen.gi_suspended) # True
print(next(gen)) # 2
print(gen.gi_suspended) # True
print(next(gen)) # 3
print(gen.gi_suspended) # True
print(next(gen)) # 4
print(gen.gi_suspended) # True
print(next(gen)) # 5
print(gen.gi_suspended) # True
print(next(gen)) # StopIteration:
A yield statement can be assigned to a variable to be used with or without send() as shown below:
*Memo:
-
send() starts or resumes the generator, sends a value into the variable assigned a
yieldstatement only when resuming the generator, executes ayieldstatement to return a value and pauses the generator or raises StopIteration if the generator is terminated:- The 1st argument is
value(Required-Type:Any):- It must be
Nonewhen starting the generator. - Don’t use value=.
- It must be
- The 1st argument is
- The variable assigned a yield statement has
Noneby default. -
yield fromonly with a generator(yield from generator) works withsend()properly.
<yield without send()>:
def func():
v1 = yield 0
print(v1, 'func')
v2 = yield 1
print(v2, 'func')
v3 = yield 2
print(v3, 'func')
gen = func()
print(next(gen)) # 0
print(next(gen)) # None func
# 1
print(next(gen)) # None func
# 2
print(next(gen)) # StopIteration:
<yield with send()>:
def func():
v1 = yield 0
print(v1, 'func')
v2 = yield 1
print(v2, 'func')
v3 = yield 2
print(v3, 'func')
gen = func()
print(gen.send(None)) # 0
print(gen.send('A')) # A func
# 1
print(gen.send('B')) # B func
# 2
print(gen.send('C')) # C func
print(gen.send('D')) # StopIteration:
def func():
v1 = yield 0
print(v1, 'func')
v2 = yield 1
print(v2, 'func')
v3 = yield 2
print(v3, 'func')
gen = func()
print(gen.send('A'))
# TypeError: can't send non-None value to a just-started generator
<yield from without send()>:
def func():
v1 = yield from [0, 1]
print(v1, 'func')
v2 = yield from [2, 3]
print(v2, 'func')
v3 = yield from [4, 5]
print(v3, 'func')
gen = func()
print(next(gen)) # 0
print(next(gen)) # 1
# None func
print(next(gen)) # 2
print(next(gen)) # 3
# None func
print(next(gen)) # 4
print(next(gen)) # 5
# None func
print(next(gen)) # StopIteration:
<yield from with send()>:
def sub_func():
v1 = yield 0
print(v1, 'sub_func')
v2 = yield 1
print(v2, 'sub_func')
v3 = yield 2
print(v3, 'sub_func')
def func():
v = yield from sub_func()
print(v, 'func')
gen = func()
print(gen.send(None)) # 0
print(gen.send('A')) # A sub_func
# 1
print(gen.send('B')) # B sub_func
# 2
print(gen.send('C')) # C sub_func
# None func
# StopIteration:
def func():
v1 = yield from [0, 1]
print(v1, 'func')
v2 = yield from [2, 3]
print(v2, 'func')
v3 = yield from [4, 5]
print(v3, 'func')
gen = func()
print(gen.send('A'))
# TypeError: can't send non-None value to a just-started generator
def func():
v1 = yield from [0, 1]
print(v1, 'func')
v2 = yield from [2, 3]
print(v2, 'func')
v3 = yield from [4, 5]
print(v3, 'func')
gen = func()
print(gen.send(None)) # 0
print(gen.send('A'))
# AttributeError: 'list_iterator' object has no attribute 'send'
A yield statement cannot be assigned to a for statement as shown below:
def func():
for v in yield [0, 1, 2]:
# for v in yield from [0, 1, 2]:
print(v)
# SyntaxError: invalid syntax
This content originally appeared on DEV Community and was authored by Super Kai (Kazuya Ito)
