The next part of the syntax that might be unfamiliar is this @ sign and
something that comes after the @ sign. Now we sort of know what it does.
It's basically saying when the user hits up this path
which is what's called the home route, basically when you go to a website,
for example, www.google.com
and you go to the first forward slash well, that is going to be the home.
And it knows that when you go there you want to see the home page.
So that's effectively what we're saying here.
When the user navigates to our URL with just a forward slash they want to see
the homepage and so we're going to show them hello world.
But what is this syntax exactly? Well,
this is code a Python decorator
and this is something that you'll see in more advanced Python projects.
So what exactly is a decorator? Well,
let's imagine that you have a bunch of functions in your class or in your
module
and you want to add some functionality to each of these functions. Well then you
might use a decorator function to do that.
Essentially you can think of a decorator function as a function
that's going to give additional functionality to an existing function. In order
to really understand this,
we have to understand a couple of other concepts as well.
So I'm going to do a couple of demos in this Repl.it
and if you head to this URL or find it in the course resources,
you'll be able to see all the code that I've written in this file.
So a long time ago,
we learned about Python functions and we know that a function allows us to
have specific packages of functionality,
allows us to add inputs, to increase the reusability of the function,
and also allows us to get outputs from the function which we can pass into
another function or do something with it. As an example,
we've got four very simple functions, add, subtract, multiply,
and divide that uses all three components of a function.
Now, what if we wanted to get a little bit fancier? Well,
one of the things about Python functions is that they are known as first-class
objects,
which basically means that you can pass a function around as an argument,
just like what you could do with an integer, a string or a float, it's treated
identically.
That means we can take these functions and we can build another function that
uses these functions. Let's say I create a calculate function
which takes a calc_function
and then the n1 and n2.
Inside this calculate function,
I'm going to call the function that was passed in and give it the values
n1 and n2 that was also passed in.
So now when I call the calculate function,
I'm going to pass in the name of one of these functions and then some numbers.
Those numbers are gonna become the input for this specified function
and then we're going to return the result of that calculation.
So now lower down,
I can call my calculate function, pass in the name of a function
so for example our multiply function, and then pass in some numbers,
for example, two and three. Now let the output that's returned
be our results
and let's go ahead and print this result. And you can see we get six.
So basically it has now multiplied two by three. Now,
if I change this to one of the other functions, add,
and I run this again, you can see instead of six, I'm now getting five.
The ability for us to treat functions as first-class objects basically means
that we can pass them around as if they were just any other argument
like a number or a string or a floating point number.
And then later we can activate them by adding the brackets around them and then
any necessary inputs. Now, the next concept
which you might've come across
but we haven't really used it a lot is the concept of nested functions.
Functions can also be nested inside other functions.
For example, if I create a function called outer_function
and this function is just going to print and say,
I'm outer. Now inside this outer_function,
I could create another function. So notice the indentation here
means that this function is now created inside this function and I'll call it
the nested_function.
So this function is simply going to print I'm
inner.
And now we have the problem of trying to call this function. Now,
because this function was declared inside this function,
its scope means that it's only accessible inside the confines of this function.
So if we were to go outside of the function, so by
indenting back to the beginning and we try to call this nested function,
then it's actually not going to work.
We're going to get a name error. It's not defined. However,
if we call this function inside this outer_function,
then it will now no longer generate an error.
So let's go ahead and trigger the outer_function by calling it in our main.
py. And when I run this, you can see it says I'm outer
and then it says I'm inner.
So this first gets executed and then this. And this I'm inner is being
printed when this line is being evaluated. Now,
one of the other things you could do is you can actually return a function from
another function.
1: Right.
0: Functions can actually be returned from other functions.
So if I make a copy of this previous function right here and comment out this
other function and all the steps before,
1: ...
0: and we only have this bit of active code,
then you can see that instead of calling this nested_function here,
I could also return it as the output.
But the important part here is I'm going to get rid of the parentheses
which means I'm no longer activating that function right here.
So now when I call this outer_function,
the output that this line is going to evaluate to is going to become the nested_
function. So you could almost store it inside a variable.
So let's say I create a variable called inner_function
which is equal to the output of the outer_function
which is basically this nested_function that's being returned. Well
then, not only can I trigger the outer_function
which is just going to give me I'm outer,
now I can also trigger the inner_function separately by calling it
and then adding the activator which is the parentheses.
So now it says I'm outer after it evaluates this line,
I'm inner after it evaluates this line. Now,
if this is confusing to you,
I recommend heading over to the course resources where I've got a link to this
Python Tutor where I've entered all the code that we've seen just now
and we can execute this code line by line.
So you can see that the first thing that happens is it looks at this outer_
function and it creates a reference to that function. Now
next, it's on this line where our outer_function is actually being executed
because it has the parentheses at the end.
So now it's actually going to go inside this outer function and go through it
line by line where it prints I'm outer and then sets up a reference to this second
function, which is the nested_function.
The nested_function can now be called by its name
which is nested_function. But the very end of the outer_function,
that function is going to be the return value. So it's going to be outputted.
Finally,
we get to the end of this line nine and we set up a reference from this variable
called inner_function to this nested_function. And finally,
when we get to the line 10 we trigger that function.
So here is our inner_function which points to this nested function
and so when we trigger this inner_function,
it's the same as triggering the nested_function.
And that is when we end up going into this function
and printing out what it says inside.
Have a play around with that to fully get to grips with all the things that you
can do with a function.
And once you're happy with all of this and you've reviewed it and you understand
everything that's going on,
then you've got the foundations to head over to the next lesson where we're
going to talk about Python decorators.