0% found this document useful (0 votes)
2 views19 pages

Understanding Recursion and Generators

The document discusses recursion and generators in programming, focusing on the Fibonacci sequence and the greatest common divisor (GCD) using both recursive and iterative methods. It explains the differences between local and global variables, including how to declare and use them, as well as the implications of variable name collisions. Additionally, it highlights the advantages and disadvantages of recursion compared to iteration, emphasizing the efficiency and readability of each approach.

Uploaded by

horace23vt
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views19 pages

Understanding Recursion and Generators

The document discusses recursion and generators in programming, focusing on the Fibonacci sequence and the greatest common divisor (GCD) using both recursive and iterative methods. It explains the differences between local and global variables, including how to declare and use them, as well as the implications of variable name collisions. Additionally, it highlights the advantages and disadvantages of recursion compared to iteration, emphasizing the efficiency and readability of each approach.

Uploaded by

horace23vt
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

3/20/25, 8:33 PM Recursion and Generator

Recursion and Generator


CS1302 Introduction to Computer Programming

In [2]: %reload_ext divewidgets

# Set LLM alias


%load_ext jupyter_ai
%ai update chatgpt dive:chat

Out[2]: Updated target of alias chatgpt


Content ps. This lecture introduces some advanced topics and thus is more difficult
than previous ones.
Recursion
Global variables
Generator

Recursion
Fibonacci number: 0, 1, 1, 2, 3, 5, 8, 13, 21,....
Consider computing the Fibonacci number of order $n$: $$ F_n := \begin{cases}
F_{n-1}+F_{n-2} & n>1 \kern1em \text{(recurrence)}\\ 1 & n=1 \kern1em \text{(base
case)}\\ 0 & n=0 \kern1em \text{(base case)}. \end{cases}$$ Fibonacci numbers have
practical applications in generating pseudorandom numbers.
Can we define the function by calling the function itself?
Recursion) is a function that calls itself (recurs).
To be more specific, recursion is a method of solving a problem where the solution
depends on solutions to smaller instances of the same problem
In [3]: %%optlite -r -h 450
def fibonacci(n):
if n > 1:
return fibonacci(n - 1) + fibonacci(n - 2) # recursion
elif n == 1:
return 1
else:
return 0

fibonacci(3)

Out[3]: 2

[Link] and [Link] 1/19


3/20/25, 8:33 PM Recursion and Generator

Out[3]: OPTWidget(value=None, height=450, script='def fibonacci(n):\n if n >


1:\n return fibonacci(n - 1) + …

Exercise Write a function gcd that implements the Euclidean algorithm for the
greatest common divisor: $$\operatorname{gcd}(a,b)=\begin{cases}a & b=0\\
\operatorname{gcd}(b, a\operatorname{mod}b) & \text{otherwise} \end{cases}$$
In [5]: def gcd(a, b):
# YOUR CODE HERE
if b==0:
return a
else:
return gcd(b, a%b) #recursion: call itself but with different par

gcd(15, 35)

Out[5]: 5

Is recursion strictly necessary?


No. We can always convert a recursion to an iteration.
E.g., the following computes the Fibonnacci number of order using a while loop
instead.
In [6]: %%optlite -r -h 550
def fibonacci_iteration(n):
if n > 1:
x, y = 0, 1 # next two Fibonacci numbers
while n > 1:
x, y, n = y, x + y, n - 1
return y
elif n == 1:
return 1
else:
return 0

fibonacci_iteration(3)

Out[6]: 2

Out[6]: OPTWidget(value=None, height=550, script='def fibonacci_iteration(n):\n


if n > 1:\n x, y = 0, 1 # n…

In [7]: # more tests


for n in range(5):
assert fibonacci(n) == fibonacci_iteration(n)

In the example above, we have x, y, n = y, x + y, n - 1, is it equivalent to the code


below?
x=y
y=x+y
n=n-1
[Link] and [Link] 2/19
3/20/25, 8:33 PM Recursion and Generator

The answer is NO
In [8]: %%optlite -r -h 550
#how can we exchange the value of two variables a and b?
#is the following code correct?
a=1
b=5

a=b
b=a

print('a is',a,'b is', b)

a is 5 b is 5
Out[8]: OPTWidget(value=None, height=550, script="#how can we exchange the value
of two variables a and b? \n#is the f…

In [9]: %%optlite -r -h 650


#the following is the correct way to exchange two variables
#we need a temporary variable to store the value of a
a=1
b=5

c=a
a=b
b=c

print('a is',a,'b is', b)

a is 5 b is 1
Out[9]: OPTWidget(value=None, height=650, script="#the following is the correct
way to exchange two variables\n#we nee…

In [10]: #can we make it simpler?


a=1
b=5

a,b = b,a #in this way, we don't need temporary variable


print('a is',a,'b is', b)

#similarly, if we have three variables


x=1
y=5
z=6

x, y, z = z, x, y #in this way, we don't need temporary variable


print('x is',x,'y is', y, 'z is', z)

a is 5 b is 1
x is 6 y is 1 z is 5

Exercise
We can always convert a recursion to an iteration. Why?
{hint}
See the [recursion vs iteration]
([Link]

[Link] and [Link] 3/19


3/20/25, 8:33 PM Recursion and Generator

In [12]: %%ai chatgpt -f text

In one paragraph, explain why we can convert a recursion to an iteration

Out[12]: We can convert a recursion to an iteration in Python because both method


s are used to solve problems that have a repetitive pattern. Recursion u
ses function calls to solve a problem by breaking it down into smaller i
nstances of the same problem, whereas iteration uses a loop to repeatedl
y execute a set of instructions. The key to converting recursion to iter
ation lies in understanding that each recursive function call adds a lay
er to the system's call stack, which can be mimicked using a loop that i
terates over a data structure such as a stack or queue. By using a data
structure to store the intermediate results and a loop to process them,
we can avoid the recursive function calls and achieve the same result, t
hus converting a recursive solution to an iterative one.

{admonition}
The step-by-step execution of the recursion is indeed how
python implements a recursion as an iteration.

Exercise Implement gcd_iteration using a while loop instead of a recursion.


In [11]: %%optlite -r -h 550
def gcd_iteration(a, b):
# YOUR CODE HERE
while b:
a, b =b, a % b
return a

gcd_iteration(3 * 5, 5 * 7)

Out[11]: 5

Out[11]: OPTWidget(value=None, height=550, script='def gcd_iteration(a, b):\n


# YOUR CODE HERE\n while b:\n …

What are the benefits of recursion?


Recursion is often shorter and easier to understand.
It is also easier to write code by wishful thinking or declarative programming as
supposed to imperative programming.
Is recusion more efficient than iteration?
No, let's see the example below
In [13]: import time #import package time because we need to use [Link]()
n=30 #if the number is too large, it takes a while to run
time1=[Link]() #get the current system time
fibonacci(n)
time2=[Link]() #get the current system time
print('Running time of recursion:{:.5f} seconds'.format(time2-time1))

Running time of recursion:0.11356 seconds

[Link] and [Link] 4/19


3/20/25, 8:33 PM Recursion and Generator

In [14]: n=30
time1=[Link]() #get the current system time
fibonacci_iteration(n)
time2=[Link]() #get the current system time
print('Running time of iteration:{:.5f} seconds'.format(time2-time1))

Running time of iteration:0.00004 seconds

To see why recursion is slow, we will modify fibonacci to print each function call
as follows.
In [15]: #this function show how many functions are called in order to calculate f
def fibonacci(n):
'''Returns the Fibonacci number of order n.'''
print('fibonacci({!r})'.format(n)) #everytime, we print the funtion
return fibonacci(n - 1) + fibonacci(n - 2) if n > 1 else 1 if n == 1

fibonacci(5)

fibonacci(5)
fibonacci(4)
fibonacci(3)
fibonacci(2)
fibonacci(1)
fibonacci(0)
fibonacci(1)
fibonacci(2)
fibonacci(1)
fibonacci(0)
fibonacci(3)
fibonacci(2)
fibonacci(1)
fibonacci(0)
fibonacci(1)
Out[15]: 5

There are many redundant computations. E.g.,, fibonacci(3) is called twice


because
fibonacci(5) calls fibonacci(4) and fibonacci(3) .
fibonacci(4) then calls fibonacci(3) and fibonacci(2) .

Global Variables
reference book) and Closures (chapter 8.1 in
Actually, we already introduced global variables and local variables in Lecture 4:
using functions. Now, we'll introduce more details.
Local variable vs Global variable
A local variable is a variable declared inside a function. It can be only accessed
inside a function.

[Link] and [Link] 5/19


3/20/25, 8:33 PM Recursion and Generator

A global variable is a variable declared outside of the function or in global scope.


This means that a global variable can be accessed inside or outside of the
function.
Rules for global/local variables:
1. A local variable must be defined within a function.
2. An assignment defines a local variable except in a global statement.
Explanations about the two rules above.
global variables are defined outside a function

if we want to change its value in a function, we must use keyword global to


declare it; otherwise, we just create a local variable
otherwise, global is not necessary, but it's always a good habit to use
global to decare global variables to make your code easy to read

See example below


In [16]: x=5 #x is a global variable

def add_1():
#global x
x = 10 #this x is a local variable
return x

print(add_1())

print(x)

10
5

In [17]: x=5 #x is a global variable

def add_1():
global x #if you want to use global variable x in a function, you mus
x= 10
return x

print(add_1())
print(x)

10
10

Then, the following code also uses global variable x in function add_1() , but
doesn't use global to declare it, why it can be executed without any error?
In [18]: x=5 #x is a global variable

def add_1():
#global x
y = x + 1
return y

[Link] and [Link] 6/19


3/20/25, 8:33 PM Recursion and Generator

print(add_1())
print(x)

6
5

This is because we don't change the value of global variable x , so we don't need to
declare it.
In [21]: x=5 #x is a global variable

def add_1():
# global x
x = x + 1 # error because we change the value of global variable x
return x

print(add_1())
print(x)

--------------------------------------------------------------------------
-
UnboundLocalError Traceback (most recent call las
t)
Cell In[21], line 8
5 x = x + 1 # error because we change the value of global variab
le x
6 return x
----> 8 print(add_1())
9 print(x)

Cell In[21], line 5, in add_1()


3 def add_1():
4 # global x
----> 5 x = x + 1 # error because we change the value of global variab
le x
6 return x

UnboundLocalError: cannot access local variable 'x' where it is not associ


ated with a value

In [32]: %%ai chatgpt -f text

In one paragraph, explain why we get UnboundLocalError when we change the

Out[32]: In Python, when we try to modify a global variable within a function wit
hout declaring it as global, we get an UnboundLocalError because Python
treats the variable as local by default. When the assignment operation i
s encountered, Python looks for a local variable with that name, but sin
ce it hasn't been initialized yet, it raises an UnboundLocalError, indic
ating that the local variable is referenced before assignment. This erro
r occurs because Python's scoping rules dictate that a variable is consi
dered local to a function if it's assigned a value anywhere within that
function, even if the assignment happens after the variable is reference
d. Since the global variable hasn't been explicitly declared, Python doe
sn't look for it in the global scope, resulting in the UnboundLocalError
when trying to modify its value.

name collision

[Link] and [Link] 7/19


3/20/25, 8:33 PM Recursion and Generator

If a function defines a local variable with the same name as a global variable, the
global variable become inaccessible to code within the function. We say the local
variable hides the like-named global variable from code in the function’s body. ---
page 235 of reference book
In [22]: #my_name is a global variable
my_name='Global variable'

#in this function, my_name is a local variable, here the global variable
def print_name():
my_name='Local variable' #local variable will hide global variable i
print(my_name)

print_name() #this line will print local variable my_name


print(my_name) #this line will print global variable my_name

Local variable
Global variable

With global variables


codes are less predictable, more difficult to reuse/extend, and
tests cannot be isolated, making debugging difficult.
More disadvantages are explained on page 235-237 in reference book.
Nested function and Nonlocal variable
A function defined inside another function is called a nested function .
Nested functions can access variables of the enclosing scope.
In the following example, we can see that the nested printer() function is able to
access the non-local msg variable of the enclosing function.
In [23]: s="CS1302" #this is a global variable

def print_msg(msg):
# This is the outer enclosing function
s1=msg #s1 is a nonlocal variable
def printer():
# This is the nested function
nonlocal s1 #we need to use nonlocal to declare s1 in the inner f
global s
s2=s1 #s2 is a local variable
print(s2)
print(s)

printer()

# We execute the function


print_msg("Hello")

Hello
CS1302

global variables are defined outside a function


[Link] and [Link] 8/19
3/20/25, 8:33 PM Recursion and Generator

if we use it in an assignment, we must use keyword global to declare it


if we don't use assignment operator to change its value, we don't need to
use keyword global to declare it
Similarly,
Nonlocal variables are defined in the outer function

if we use it in an assignment, we must use keyword nonlocal to declare it


if we don't use assignment operator to change its value, we don't need to
use keyword nonlocal to declare it
Global vs Local vs Nonlocal
More information can be found in this page
In [24]: def outer():
x = 1 #this x is a nonlocal variable
def inner():
y=x+1 # if we don't change its value, we don't need to use nonloc
print(y)

inner()

outer()

In [25]: def outer():


x = 1 #this x is a nonlocal variable
def inner():
nonlocal x #if we want to change x's value in the inner function,
x=x+1
print(x)

inner()

outer()

Python Closures
In the example above, we have called the inner function inside the outer function. The
inner function becomes a closure when we return the inner function instead of calling
it.
What happens if we don't call the inner function?
Run the code below to see the result
In [26]: def outer():
x = 1 #this x is a nonlocal variable
def inner():
nonlocal x #if we want to change x's value in the inner function,

[Link] and [Link] 9/19


3/20/25, 8:33 PM Recursion and Generator

x=x+1
print(x)

#inner()

outer()

To solve this problem, we can create a closure in Python if


We have a nested function, i.e. function within a function
The nested function refers to a variable of the outer function
The enclosing function returns the enclosed function
In [28]: # %%optlite -r -h 650
def print_msg(msg):
# This is the outer enclosing function
s1=msg #s1 is a nonlocal variable
def printer():
# This is the nested function
nonlocal s1 #we need to use nonlocal to declare s1 in the inner f
s2=s1 #s2 is a local variable
print(s2)

return printer #we return printer instead of execute it using printe

myFunction=print_msg("Hello")
myFunction()

del print_msg #even we delete print_msg, the value "Hello" is still reme
myFunction()

Hello
Hello

In [29]: str1="hello"
print(str1)

del str1
print(str1)

hello
--------------------------------------------------------------------------
-
NameError Traceback (most recent call las
t)
Cell In[29], line 5
2 print(str1)
4 del str1
----> 5 print(str1)

NameError: name 'str1' is not defined

Here, the call to outer function returns the inner function. This then gets
assigned to ‘myFunction’. Now when we call myFunction, it prints ‘Hello’ (which
was earlier given as an argument to outer).
[Link] and [Link] 10/19
3/20/25, 8:33 PM Recursion and Generator

Even after ‘outer’ finishes its execution and all its variables go out of scope, the
value passed to its argument is still remembered.
This is the beauty of closures! We can access the values of a function that no
longer exists.
More information can be found here
Function as data
We can treat function as data (int, string etc).
so a function name can be used as parameter
we can also return a function
See example below
In [30]: #this example shows we can use funtion name as input parameters and retur
def add(x, y):
"""
Adds the parameters x and y and returns the result
"""
return x + y

def multiply(x, y):


"""
Multiplies the parameters x and y and returns the result
"""
return x * y

def evaluate(f, x, y):


"""
Calls the function f with parameters x and y:
f(x, y)
"""
return f(x,y)

"""
Tests the add, multiply, and evaluate functions
"""
print(add(2, 3))
print(multiply(2, 3))
print(evaluate(add, 2, 3))
print(evaluate(multiply, 2, 3))

5
6
5
6

Generator
We can use iteration/loop to generate a sequence of value. Another way to generate
a sequence of value one-by-one is to write a generator.
[Link] and [Link] 11/19
3/20/25, 8:33 PM Recursion and Generator

A generator is a programming object that produces (that is, generates) a sequence


of values. ---page 280 in reference book
How to create a generator?
method 1: use generator_name=(iterable object)
must be enclosed by parentheses ()
In [33]: fibonacci_generator = (fibonacci_iteration(n) for n in range(3))
print(type(fibonacci_generator))

#another example
x=(i for i in range(5))
print(type(x))

#what happens if there's no parentheses ()-->error


x= (i for i in range(5))
print(type(x))

print(list(range(5))) #convert range object to a list


print(*range(5)) #use unpacking operator to unpack a range object

<class 'generator'>
<class 'generator'>
<class 'generator'>
[0, 1, 2, 3, 4]
0 1 2 3 4

The above uses a generator expression to define fibonacci_generator .


How to obtain items from a generator?
We can use the next function.
next()

it accepts a generator object and returns the next value in the generator’s
sequence
we'll get an error if we ask the generator to provide a value after the final value in
its sequence
In [34]: x=(i for i in range(5)) #0 1 2 3 4
print(next(x)) #0
print(next(x)) #1
print(next(x)) #2
print(next(x)) #3
print(next(x)) #4
print(next(x)) #raise an error cause there's no next value

0
1
2
3
4

[Link] and [Link] 12/19


3/20/25, 8:33 PM Recursion and Generator

--------------------------------------------------------------------------
-
StopIteration Traceback (most recent call las
t)
Cell In[34], line 7
5 print(next(x)) #3
6 print(next(x)) #4
----> 7 print(next(x)) #raise an error cause there's no next value

StopIteration:

A generator object is iterable, i.e., it implements both __iter__ and __next__


methods that are automatically called in a for loop as well as the next function.
In [35]: x=(i for i in range(5)) #0 1 2 3 4
#we can access the elements in a generator using for loop
for i in x:
print(i)

0
1
2
3
4

Is fibonacci_generator efficient?
No again due to redundant computations.
A better way to define the generator is to use the keyword yield :
In [37]: %%optlite -h 500
def fibonacci_sequence(Fn, Fn1, stop):
while Fn < stop:
yield Fn # return Fn and pause execution
Fn, Fn1 = Fn1, Fn1 + Fn

for fib in fibonacci_sequence(0, 1, 5):


print(fib)

Out[37]: OPTWidget(value=None, height=500, script='def fibonacci_sequence(Fn, Fn


1, stop):\n while Fn < stop:\n …

{important}

1. `yield` causes the function to return a *generator*


without executing the function body.
1. Calling `__next__` resumes the execution, which
- pauses at the next `yield` expression, or
- raises the `StopIterationException` at the end.

{important}

return vs yield
- `return` will return the data and terminate a function
immediately

[Link] and [Link] 13/19


3/20/25, 8:33 PM Recursion and Generator

- `yield` just pauses the function, and will continue from


there in next function call

In [38]: %%ai chatgpt -f text

In one paragraph, explain what is the difference between return and yield

Out[38]: The primary difference between `return` and `yield` in Python is the way
they handle the flow of a function's execution. When a function encounte
rs a `return` statement, it terminates the function's execution and send
s the result back to the caller, after which the function's local variab
les are destroyed. In contrast, when a function encounters a `yield` sta
tement, it pauses the function's execution, returns the yielded value to
the caller, but retains the function's local variables, allowing the fun
ction to resume execution from the point where it left off when called a
gain. This difference makes `yield` particularly useful for creating gen
erators, which can produce a sequence of values on-the-fly, without havi
ng to store them all in memory at once, whereas `return` is typically us
ed for functions that compute a single value or a collection of values a
nd return them all at once.

In [39]: #a normal function


def my_gen():
n = 1
print('This is printed first')
return n # function will stop here, because return statement returns

n += 1
print('This is printed second')
return n

n += 1
print('This is printed at last')
return n

#run this function


my_gen()

This is printed first


Out[39]: 1

In [40]: # A simple generator function


def my_gen():
n = 1
print('This is printed first')
# Generator function contains yield statements
yield n

n += 1
print('This is printed second')
yield n

n += 1
print('This is printed at last')
yield n

# Using for loop

[Link] and [Link] 14/19


3/20/25, 8:33 PM Recursion and Generator

for item in my_gen():


print(item)

This is printed first


1
This is printed second
2
This is printed at last
3

In [41]: #A simple generator function


def my_gen():
n = 1
print('This is printed first')
# Generator function contains yield statements
yield n

n += 1
print('This is printed second')
yield n

n += 1
print('This is printed at last')
yield n

#we can use next() to replace for loop to continue to the next yield expr

#it returns a generator object, but doesn't start execution immediately


a=my_gen()
#we can get all the numbers using next()
value=next(a)
print(value)
# once the function yields, the function is paused and the control is tra
# local variables and their states are remembered between successive call
value=next(a)
print(value)
value=next(a)
print(value)

This is printed first


1
This is printed second
2
This is printed at last
3

So far, a generator can only generate some data, can it receive data?
Yes, we can use send() function
send() function can send a value to a generator
The send() method returns the next value yielded by the generator ,
or raises StopIteration if the generator exits without yielding another value.
When send() is called to start the generator, it must be called with None as the
argument, because there is no yield expression that could receive the value.
In [42]: def my_gen():
n=1

[Link] and [Link] 15/19


3/20/25, 8:33 PM Recursion and Generator

received_value=yield n #this is how we receive data


print("I received the first number:",received_value)

n=n+1
received_value=yield n
print("I received the second number:", received_value)

n=n+1
received_value=yield n
print("I received the third number:", received_value)

a=my_gen()

generated_value=next(a)
print("I generate:", generated_value)

generated_value=[Link](100)
print("I generate:",generated_value)

generated_value=[Link](200)
print("I generate:",generated_value)

#this send() will cause error because there's no more yield expression
generated_value=[Link](300)

I generate: 1
I received the first number: 100
I generate: 2
I received the second number: 200
I generate: 3
I received the third number: 300
--------------------------------------------------------------------------
-
StopIteration Traceback (most recent call las
t)
Cell In[42], line 27
24 print("I generate:",generated_value)
26 #this send() will cause error because there's no more yield expres
sion
---> 27 generated_value=[Link](300)

StopIteration:

Exercise yield can be both a statement and an expression. As an expression:


The value of a yield expression is None by default, but
it can be set by the [Link] method.
Add the document string to the following function. In particular, explain the effect of
calling the method send on the returned generator.
In [ ]: def fibonacci_sequence(Fn, Fnn, stop):
# YOUR CODE HERE
raise NotImplementedError()
while Fn < stop:
value = yield Fn
if value is not None:
Fnn = value # set next number to the value of yield expressi

[Link] and [Link] 16/19


3/20/25, 8:33 PM Recursion and Generator

Fn, Fnn = Fnn, Fnn + Fn

fibonacci_generator = fibonacci_sequence(0, 1, 5)
print(next(fibonacci_generator))
print(fibonacci_generator.send(2))
for fib in fibonacci_generator:
print(fib)

In [44]: #answer to the above question

def fibonacci_sequence(Fn, Fnn, stop):


### BEGIN SOLUTION
"""Return a generator that generates Fibonacci numbers
starting from Fn and Fnn to stop (exclusive).
[Link](value) sets and returns the next number as value."""
### END SOLUTION
while Fn < stop:
value = yield Fn
if value is not None:
Fnn = value # set next number to the value of yield expressi
Fn, Fnn = Fnn, Fnn + Fn

fibonacci_generator = fibonacci_sequence(0, 1, 5)
print(next(fibonacci_generator))
print(fibonacci_generator.send(2))
for fib in fibonacci_generator:
print(fib)

0
2
2
4

In [45]: %%ai chatgpt -f text

Explain the yield and send in python.

[Link] and [Link] 17/19


3/20/25, 8:33 PM Recursion and Generator

Out[45]: **Yield in Python**

In Python, `yield` is a keyword used to define generators, which are a t


ype of iterable. When a function contains a `yield` statement, it become
s a generator function. When called, the function returns a generator it
erator, which can be used to retrieve values from the function.

Here's how `yield` works:

1. When a generator function is called, it executes until it reaches a `


yield` statement.
2. The value specified by the `yield` statement is returned to the calle
r.
3. The function's execution is paused, and its local variables are retai
ned.
4. When the `next()` function is called on the generator iterator, the f
unction resumes execution from the point where it left off.

Example:
```python
def infinite_sequence():
num = 0
while True:
yield num
num += 1

seq = infinite_sequence()
print(next(seq)) # prints 0
print(next(seq)) # prints 1
print(next(seq)) # prints 2
```

**Send in Python**

In Python, `send()` is a method used to send a value to a generator, whi


ch can then be received by the `yield` statement. This allows for two-wa
y communication between the generator and the caller.

Here's how `send()` works:

1. When a generator function contains a `yield` statement with an expres


sion, it can receive a value from the caller using the `send()` method.
2. The `send()` method sends a value to the generator, which is then ass
igned to the variable on the right-hand side of the `yield` statement.
3. The generator function resumes execution from the point where it left
off.

Example:
```python
def echo():
while True:
received = yield
print("Received:", received)

echo_gen = echo()
next(echo_gen) # advances the generator to the first yield
echo_gen.send("Hello") # prints "Received: Hello"
echo_gen.send("World") # prints "Received: World"
```

[Link] and [Link] 18/19


3/20/25, 8:33 PM Recursion and Generator

Note that `send()` can only be used after the generator has been advance
d to the first `yield` statement using `next()`. If `send()` is called b
efore `next()`, a `TypeError` is raised.

In summary, `yield` is used to produce values from a generator, while `s


end()` is used to send values to a generator, allowing for two-way commu
nication between the generator and the caller.

A short Summary (more information in Chapter 8.8)


1. What is recursion and how to use recursion (Important!)
2. Global variables and closure
3. What's a generator (Important!)
A generator is a programming object that produces (that is, generates) a
sequence of values
4. How to create a generator
using (iterable object)
use yield expression
5. How to obtain the elements in generator?
use next()
use for loop
6. How to use send() function
More tutorials about Generator can be found here
In [ ]:

[Link] and [Link] 19/19

You might also like