Python 03: Iterator and Generator


🤔 Let's talk about the difference between iteration and generation in Python and how to construct the Generators with the yield statement. Generators allow us to generate as we go along, instead of holding everything in memory.
Generator functions allow us to write a function that can send back a value and then later resume to pick up where it left off. This type of function is a generator in Python, allowing us to generate a sequence of values over time. The main difference in syntax will be the use of a yield statement.
So let's check out some codes! 🧑🏻‍💻

Generator


gencubes(n)

# Generator function for the cube of numbers (power of 3)
def gencubes(n):
	for num in range(n):
    	yield num**3
       
for x in gencubes(10):
	print(x)
    
> 0
1
8
27
64
125
216
343
512
729    
We have a generator function we don't have to keep track of every single cube we created.
Generators are best for calculating large sets of results (particularly in calculations that involve loops themselves) in cases where we don't want to allocate the memory for all of the results at the same time.
(関数を切り替えると、出力値をメモリに1つずつ保存する必要がないので、非常に効率的です!!😎 )

normal function and generator function

def fibon(n):
	a = 1
    b = 1
    output = []
    
    for i in range(n):
    	output.append(a)
       	a,b = b, a+b
        
    return output

fibon(10)
> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
def genfibon(n):
	a = 1
    b = 1
    for i in range(n):
    	yield a
        a,b = b, a+b
        
for num in genfibon(10):
	print(num)
    
> 1
1
2
3
5
8
13
21
34
55
This is function of fibonacci numbers. Notice that if we call some huge value of n (like 10000000) the second function will have to keep track of every single result, when in this case we actually only care about the previous result to generate the next one! 😎
上の2つの関数は、フィボナッチ数列を生成する同じ関数です.最初の関数はreturn値をリストに出力し、2番目の関数はgeneratorを使用します.例では、n値を10に設定しますが、1000000の大きな数を指定すると、非常に大きなメモリ、時間、演算が必要になります.しかし、generatorを使用すると、前の順序の結果のみが出力されるので、より効率的です!

Iterator


next() and iter() built-in functions


A key to fully understand generators is the next() function and the iter() function.
The next() function allows us to access the next element in a sequence.
def test_gen():
	for x in range(3):
    	yield x
        
# Assign test_gen
t = test_gen()

print(next(t))
> 0
print(next(t))
> 1
print(next(t))
> 2
print(next(t))
> 

After yielding all the values next() caused a StopIteration error. What this error informs us of is that all the values have been yielded.
Notice
We don't get this error in for loop? Because...
A for loop automatically catches this error and stops calling next() .
(for loopを使用すると、このエラーを自動的にキャプチャし、next()メソッドの読み込みを停止するので、for loopを使用する場合は、このエラーを心配する必要はありません!)😎 )
s = 'hello'

# Iterate over string
for let in s:
	print(let)
  
output:  
> 
h
e
l
l
o
Remember that strings are iterables ???
But that doesn't mean the string itself is an iterator ! what...?!! 🤨
next(s)

What this error tells us that a string object supports iteration, but we can't directly iterate over it as we could with a generator function. The iter() function allows us to do that.
s_iter = iter(s)
next(s_iter)
> 'h'
next(s_iter)
> 'e'