What is the difference between normal function and generator function?
I am trying to understand the below methodology,
In [26]: def generator():
....: print 'generator function hits'
....: for i in range(3):
....: yield i
....:
In [27]: def normal():
....: print 'normal function hits'
....: return range(3)
....:
In [28]: gen = generator()
In [29]: type(gen)
Out[29]: generator
In [30]: fun = normal()
normal function hits
In [31]: type(fun)
Out[31]: list
Here my research from the above code, 26 is the generator()
function and 27 is the normal()
function, when I have assigned generator()
function to gen variable I haven't seen any print message like generator function hits, But if I have assigned the normal()
function to fun variable, I have seen the print message like normal function hits. My question is why generator() function not hit ?
>Answer
The behavior you're observing is due to how generators and normal functions work in Python. Let's break it down.
Normal Function (normal
)
When you call a normal function like normal()
, it runs immediately and executes all of its code, including the print()
statement. Since normal()
returns a list, Python evaluates the entire function and then returns the result.
Here’s what happens in the code:
fun = normal()
- The
normal()
function is called. - The
print('normal function hits')
statement is executed. - The function then returns
range(3)
, which is converted to a list by Python 2.x (range()
in Python 2 returns a list, whereas in Python 3, it returns an iterator). - The result (a list) is assigned to the
fun
variable.
Thus, the print statement is shown immediately because the entire function is executed right away.
Generator Function (generator
)
On the other hand, generators work differently. A generator function does not execute its code when you call it. Instead, it returns a generator object, which is an iterator that yields values one by one, only when requested.
When you do:
gen = generator()
- The
generator()
function is not executed immediately. Instead, it returns a generator object, and the code inside the function is not run yet. - The
print('generator function hits')
statement is not executed at this point because the generator hasn't been iterated over yet.
The function will only execute (and the print
statement will be shown) when you start iterating over the generator. For example:
for value in gen:
print(value)
This will trigger the generator to start yielding values, and you'll see the print statement.
Why It Happens:
- Normal functions: Execute all their code immediately and return a value (like a list or another object).
- Generator functions: Do not execute immediately. They return a generator object, which only starts executing when you iterate over it.
Example to Illustrate:
def generator():
print('generator function hits')
for i in range(3):
yield i
# Create a generator object
gen = generator() # Nothing happens yet
# To actually run the generator, you need to iterate over it
for value in gen:
print(value)
Output:
generator function hits
0
1
2
Notice that print('generator function hits')
is only executed when we iterate over the generator (via the for
loop).
In Your Original Code:
You assigned the generator object to gen
, but did not iterate over it, so the function didn't execute, and the print statement inside the generator was never reached.
gen = generator() # This does NOT print anything yet
To make it print, you need to consume the generator by iterating over it, like this:
for _ in gen:
pass # This will trigger the execution of the generator
Summary:
- Normal functions execute immediately and return a value.
- Generator functions return an iterator, which is lazy, meaning the function only runs when you start iterating over it.
- In your example, the generator's
print
statement is only hit when you iterate over the generator object.