Hello all.
So welcome back and let us continue our discussion with the question which I have given to all of you
in the last class.
That was can a function call itself as well?
So now let us understand that and do it directly in the code.
So this is some code which we saw and wrote the last time.
Right.
To print the numbers from 5 to 1.
What I effectively want to you to do is instead of calling or using all these functions, can I do something
like this where I will be using this print num function only.
And this print function is basically gonna do all the things which all of these my five functions were
doing.
Four functions were doing right.
The reason for that is because I am writing the same code in all of these functions.
I want to somehow make sure that I am able to use the code.
Plus, at every step you are going to see that my problem is actually getting smaller.
So I start with printing five, then four, then three, and I effectively have to stop in the end at
I would say one, right?
So now for the time being, let me just remove all these codes, remove all these functions, and now
try to use this way, in this way where I am calling this function from within itself so that it will
help us to answer.
Can a function call itself as well or not?
Right.
So now let me run this code okay.
So something would happen like we saw that okay.
The code ran like there is no error or anything like such.
In the below we see that okay some 991 there is some error.
And the error says maximum recursion depth while calling a Python object.
Okay, so we will come back to this error.
But first let us try to understand what exactly would have happened.
Right.
So we see that okay from 54321 it did get printed.
But after that even zero, minus one, minus two and all the way till nine, nine, nine some things
are getting printed right.
So let us understand what exactly happens.
But first I think we did get answer to our question.
So I think that's a good time.
We can write that.
Yes, we can in fact call a function from within a function or a function can actually call itself.
Right.
So glad that we got this thing answered.
Okay.
So now I would like to also explain you a little bit concerned about the stack memory.
So what happens right.
What happens exactly is that whenever a program starts in C, Java and these languages and Python is
also actually written in top of C language.
They all start with a stack memory, right?
So they take a stack memory with them and they basically start with them.
And as you keep on defining I would say variables, functions, any objects, all of these things kind
of get defined in this particular memory.
Now at some point it might happen that if you have written a faulty code or normally if you are trying
to actually, let's say load something which is more than this memory, then of course this memory can
overflow and hence we get an error of Stack overflow, right?
So a very popular website, and this is where I would say the major idea or this website came into picture.
So Stack Overflow like this is a very common error which we used to face wherein let's say our memory
which the function has kind of picked up when it started, this memory used to get filled okay, maybe
because of some faulty code, or if we are trying to load something, I would say a lot heavy.
You can think of it in a very intuitive way.
Let's say in your 5512 GB computer, you are trying to load a one GB file, right?
Of course it cannot load that and it's going to give you an error.
Okay.
So the same thing is actually kind of happening here.
The same thing is happening here where what happens is that Python sets a limit if you will feel first
let us see that okay.
What exactly happened here.
Right.
So it did print it till 53421.
But it didn't know where to stop.
Right.
It didn't know where to stop.
So what would have happened here.
What would have actually happened here is something like this.
We would have called this print num function.
This print function would have gotten a value as five.
It printed this five it actually printed this five, which we can see here and post that it called for
four.
Now this function is still actually waiting at line number three of its instance.
And another instance of print num is created.
These both instances, these both instances are actually independent of each other right.
So I called a function yes from within it.
But in a way what happened was that a new instance of this function was created where the value of num
is now four.
Now, in a similar way, this four would also be printing your number as four, and then it's going
to move forward and call another function for three.
Now again, this is also very much independent.
The code is still waiting in line three for this four function.
And this chain is going to get repeated.
So for number two num one.
The problem happens at num one.
The thing is that in our previous code which we wrote, if you all remember, we didn't call any function
after that.
Right.
But here we have not handled that case like effectively.
What is happening is that again this print num is getting called.
So this num actually went a step ahead and called for zero minus one minus two.
And something like this happened.
And they all basically kept on printing these things.
Right.
So now if I see the error, if I show you the error as well, what it is saying is that recursion depth
exceeded by calling a Python object.
So it's actually using this word recursion.
So we I will be like quickly introducing you this concept of recursion again as well.
But somewhere what has happened is that Python started off with some recursion depth okay post which
it cannot go, and that depth has overall exceeded and that is done to avoid, I would say overflow
in the stack memory, because if you will actually understand that all these functions right when they
are getting created, they are not getting destroyed because they are still in the memory waiting for
their next function to complete the work.
Like five, the print function with value five is still waiting for print function with value four.
The fourth one is waiting on three, and all of them are taking some memory in my computer, right?
So that stack memory, it can quickly get filled because it's an infinite call where each and every
number is calling for a number less than one.
Right.
So let us quickly see this again as well, so that your understanding is a lot clearer.
Now, if I show you this exactly, see what's happening.
Right.
So print num got defined.
Then I call print num.
It will print the value of this num five.
But now it is calling print again with a value less than one, which is four.
And another instance got created, but this one is still in the memory, right?
In a very similar way.
Print four.
See, see.
Now print four is actually starting the overall I would say working from the top of this function.
And it will print four.
And then it's going to call for three.
Three is going to do it work basically majorly again.
And then call for two.
And in a similar way at one as well though we should have stopped because in our last code as well,
we returned.
We didn't call any function.
Right.
So we have to somehow make sure that we are able to stop this flow of calling for zero.
But because we have not stopped as of now, this kept on just calling and we are seeing the same thing.
Stop since stack has three function on it.
Your code may have infinite recursion, right?
So now what is exactly happening?
Is that okay, this will keep on going.
And we are going to see the numbers.
But you see right.
All these methods, all these functions, they are still in the memory.
They have not actually got destroyed.
They are still waiting at their respective line three that hey, the next function is going to completed
work, and then I'm going to get basically I'm going to get over with it and then I'm going to return.
Right.
But because this is not happening, they are still waiting in the memory and they are taking up some
space.
So now with that, I hope it is clear that I yes, a function can very well call itself.
And we should actually also make sure that we fix this thing.
Right.
So how we can do that is in a very similar way, the way we wrote this code.
So in the very first code we wrote this, right.
We have not called any function here.
So using similar thing what we can do is if our number is equal to equal to one, we can return from
here.
We don't have to actually then call the next function.
And now if I run this code I'm able to see 54321 and hello world as well.
Right?
Again I will repeat what I have done.
When the number is equals to one.
I am asking this function to return specifically.
Okay, don't call for the next function in your line.
Don't call for zero, you just return and we are effectively able to do the same thing, which in the
last class we did with so many functions.
The beauty of this code is that even if you have ten now, you don't need to make these calls, right?
You don't need to make these 4 or 5, 3 or 6, seven, eight.
These functions you can call use the same functions and effectively just print these numbers from 10
to 1.
Right.
So this is something which this overall helps us to do.
And we are also able to use the principle of drive where we are not repeating our code.
Now if I just quickly show you the working of this code as well, you will see exactly how the method
or how all these functions are getting created and then getting destroyed, right?
So see first of all print num.
Get into the memory.
Print num with value five.
Then it's going to print the value of number which is five.
It's going to check hey number are you one.
It is going to say no.
So it's going to go to the next line and call for four.
Now this five is still waiting.
It's still waiting at this fifth line.
Okay.
So you will see that the green line is just that executed and next line getting executed.
Right.
So this is yes.
This is following a cycle and this overall if condition help us to break the cycle.
Now number four is going to get printed.
It's going to ask a number.
Are you one.
It's not.
So it's going to return not going to return and call for three.
In a similar way, everything is going to get printed till we call for one will basically we call this
print number value with a value of one.
When this happens.
When this happens we are going to print one.
But this time because this if condition is true, we are going to go inside this if condition, when
we go inside this if condition, we are going to just return.
Right.
And we are not going to call for this function.
Now when we return from here, it was print number with a value of two which called us.
Right.
So it is waiting in the memory.
It is still waiting in the memory and all the functions that are waiting in the memory, it's going
to get called print number two is basically the code flow is going to get returned to print number two.
Right.
So C one is going to get destroyed because it works has completed.
Now once the function completed work it gets destroyed.
And then we go forward.
And you are going to see that okay.
Print num two.
Because it has also gotten his answer.
The flow has completed.
It's going to get returned.
And it's going to get destroyed in a very similar way.
Three is going to get destroyed, four is going to get destroyed, and finally five.
Also the whole flow is completed, it's going to get destroyed, and we are going to return to this
next line, the line number 11.
And we are going to print Hello World.
Right.
So this is the overall exact flow which is happening here when we have call this function from within
and when we have also tried to basically make sure that we are able to stop this flow very similar to
what we were doing here.
But yes, this is a very smart way of writing.
It might be feeling a little weird that yes, a function is calling itself from within, but yeah,
that is very well possible in the programming languages.
So now let us, I would say just quickly write what are all learnings from this exercise because they
are going to help us a lot.
So with this exercise okay.
So with this exercise.
Two things are very very clear to us right.
Two things are clear.
So let me write these two things because you are you should remember them.
And that's going to make your understanding a lot more I would say easy.
The very first one is that functions actually wait in the memory.
functions.
Wait in the memory.
Till or unless they are resolved.
So my number print num 543.
All of them were waiting and print num with value of num five and everything.
They were waiting in the memory, right?
So they wait in the memory till everything is basically not resolved.
So they are waiting in the memory till they are resolved.
And the next learning is that when a function finishes execution.
Right?
So when a function finishes execution.
Then only.
It comes out.
Of program.
And gets deleted from a stack and gets deleted from our stack.
So that's after when our stack memory gets clear.
Right?
So these are all very, very important.
Learning.
Now let us see exactly a few more things.
So now I think we are good to just I am good to define what exactly recursion is.
So many places.
And like normally we say that recursion is.
A function.
Calling itself.
So we have written codes where print num.
We were calling print num for from this function.
Like first we saw that, but then we also saw that how our print num function can very well call the
print num again.
And that is what you can think of recursion.
So there is one more definition which I would like you to think on, I would say, and which I want
you to remember for recursion, and which is the main thing which will help you to solve lots of questions.
That is that recursion is when.
Solution of my problem or solution of a problem?
Depends.
On same smaller problem.
Now if you will see we have to print five and printing four.
Right.
It was the same problem right.
We just have to print four.
It is a smaller problem of print five in a similar way three was a smaller problem of print four.
So effectively what is happening is that from five it is the exact same problem.
The code is exactly the same, then three, then two, and then one.
Right.
So all of these are just a same problem.
But they are smaller than the previous one, right?
So they are using the same code, same logic.
And overall I am moving towards I would say overall convergence, where let's say my code is going to
get stopped, which is one in this case.
So this is exactly how we have to remember recursion.
That recursion is when solution of a problem depends on the same smaller problem.
Now we are we are good.
I hope this all exercises help you to understand a lot better on how function works.
Now we are good to start and understanding recursion with the example or use case of a factorial of
a number, right?
So this understanding of what we have done in this and the last class is going to now make your recursion
journey a lot easy.
So in the next class I'm going to now discuss and explain you a lot more in depth that how exactly can
we solve this code of writing or finding out factorial of a number with the help of a recursion and
you will see that how awesome is it?
And all these things which we have learned in this particular, I would say, class, how that is helping
us to actually understand what happens behind the scene when you write a recursive code for finding
factorial of a number.
So next, next, like let's meet in the next class everyone.
Thank you.