1
00:00:00,510 --> 00:00:05,510
The next part of the syntax that might be unfamiliar is this @ sign and

2
00:00:07,050 --> 00:00:11,460
something that comes after the @ sign. Now we sort of know what it does.

3
00:00:11,460 --> 00:00:14,790
It's basically saying when the user hits up this path

4
00:00:14,820 --> 00:00:19,170
which is what's called the home route, basically when you go to a website,

5
00:00:19,200 --> 00:00:21,540
for example, www.google.com

6
00:00:21,870 --> 00:00:26,610
and you go to the first forward slash well, that is going to be the home.

7
00:00:27,180 --> 00:00:31,080
And it knows that when you go there you want to see the home page.

8
00:00:31,530 --> 00:00:33,480
So that's effectively what we're saying here.

9
00:00:33,690 --> 00:00:38,670
When the user navigates to our URL with just a forward slash they want to see

10
00:00:38,670 --> 00:00:41,580
the homepage and so we're going to show them hello world.

11
00:00:42,210 --> 00:00:46,320
But what is this syntax exactly? Well,

12
00:00:46,320 --> 00:00:49,230
this is code a Python decorator

13
00:00:49,800 --> 00:00:54,210
and this is something that you'll see in more advanced Python projects.

14
00:00:54,540 --> 00:00:57,420
So what exactly is a decorator? Well,

15
00:00:57,450 --> 00:01:01,320
let's imagine that you have a bunch of functions in your class or in your

16
00:01:01,320 --> 00:01:02,153
module

17
00:01:02,460 --> 00:01:07,460
and you want to add some functionality to each of these functions. Well then you

18
00:01:09,780 --> 00:01:12,990
might use a decorator function to do that.

19
00:01:14,070 --> 00:01:18,570
Essentially you can think of a decorator function as a function

20
00:01:18,570 --> 00:01:23,570
that's going to give additional functionality to an existing function. In order

21
00:01:24,360 --> 00:01:25,920
to really understand this,

22
00:01:25,980 --> 00:01:29,100
we have to understand a couple of other concepts as well.

23
00:01:29,820 --> 00:01:32,430
So I'm going to do a couple of demos in this Repl.it

24
00:01:32,850 --> 00:01:36,810
and if you head to this URL or find it in the course resources,

25
00:01:37,050 --> 00:01:40,140
you'll be able to see all the code that I've written in this file.

26
00:01:41,160 --> 00:01:42,600
So a long time ago,

27
00:01:42,630 --> 00:01:47,630
we learned about Python functions and we know that a function allows us to

28
00:01:47,820 --> 00:01:50,910
have specific packages of functionality,

29
00:01:51,420 --> 00:01:56,250
allows us to add inputs, to increase the reusability of the function,

30
00:01:56,700 --> 00:02:01,380
and also allows us to get outputs from the function which we can pass into

31
00:02:01,380 --> 00:02:05,610
another function or do something with it. As an example,

32
00:02:05,610 --> 00:02:09,570
we've got four very simple functions, add, subtract, multiply,

33
00:02:09,600 --> 00:02:13,890
and divide that uses all three components of a function.

34
00:02:15,270 --> 00:02:19,350
Now, what if we wanted to get a little bit fancier? Well,

35
00:02:19,650 --> 00:02:24,650
one of the things about Python functions is that they are known as first-class

36
00:02:25,680 --> 00:02:26,513
objects,

37
00:02:26,550 --> 00:02:31,550
which basically means that you can pass a function around as an argument,

38
00:02:32,640 --> 00:02:37,440
just like what you could do with an integer, a string or a float, it's treated

39
00:02:37,710 --> 00:02:38,670
identically.

40
00:02:39,240 --> 00:02:44,240
That means we can take these functions and we can build another function that

41
00:02:44,910 --> 00:02:49,290
uses these functions. Let's say I create a calculate function

42
00:02:49,410 --> 00:02:51,870
which takes a calc_function

43
00:02:52,320 --> 00:02:54,900
and then the n1 and n2.

44
00:02:55,590 --> 00:02:57,630
Inside this calculate function,

45
00:02:57,960 --> 00:03:02,860
I'm going to call the function that was passed in and give it the values

46
00:03:02,950 --> 00:03:06,670
n1 and n2 that was also passed in.

47
00:03:07,330 --> 00:03:10,120
So now when I call the calculate function,

48
00:03:10,150 --> 00:03:15,010
I'm going to pass in the name of one of these functions and then some numbers.

49
00:03:15,370 --> 00:03:20,140
Those numbers are gonna become the input for this specified function

50
00:03:20,500 --> 00:03:24,760
and then we're going to return the result of that calculation.

51
00:03:25,420 --> 00:03:26,980
So now lower down,

52
00:03:27,010 --> 00:03:32,010
I can call my calculate function, pass in the name of a function

53
00:03:32,620 --> 00:03:37,300
so for example our multiply function, and then pass in some numbers,

54
00:03:37,360 --> 00:03:42,220
for example, two and three. Now let the output that's returned

55
00:03:42,490 --> 00:03:43,690
be our results

56
00:03:43,840 --> 00:03:48,840
and let's go ahead and print this result. And you can see we get six.

57
00:03:50,260 --> 00:03:54,670
So basically it has now multiplied two by three. Now,

58
00:03:54,700 --> 00:03:58,210
if I change this to one of the other functions, add,

59
00:03:58,750 --> 00:04:03,520
and I run this again, you can see instead of six, I'm now getting five.

60
00:04:04,240 --> 00:04:09,240
The ability for us to treat functions as first-class objects basically means

61
00:04:10,120 --> 00:04:14,080
that we can pass them around as if they were just any other argument

62
00:04:14,380 --> 00:04:17,769
like a number or a string or a floating point number.

63
00:04:18,160 --> 00:04:23,160
And then later we can activate them by adding the brackets around them and then

64
00:04:23,470 --> 00:04:27,790
any necessary inputs. Now, the next concept

65
00:04:27,820 --> 00:04:29,890
which you might've come across

66
00:04:29,980 --> 00:04:34,930
but we haven't really used it a lot is the concept of nested functions.

67
00:04:35,740 --> 00:04:39,520
Functions can also be nested inside other functions.

68
00:04:40,030 --> 00:04:43,750
For example, if I create a function called outer_function

69
00:04:45,190 --> 00:04:49,570
and this function is just going to print and say,

70
00:04:49,600 --> 00:04:54,130
I'm outer. Now inside this outer_function,

71
00:04:54,460 --> 00:04:57,970
I could create another function. So notice the indentation here

72
00:04:58,270 --> 00:05:03,270
means that this function is now created inside this function and I'll call it

73
00:05:03,430 --> 00:05:06,400
the nested_function.

74
00:05:08,020 --> 00:05:13,020
So this function is simply going to print I'm

75
00:05:15,250 --> 00:05:16,083
inner.

76
00:05:16,780 --> 00:05:21,070
And now we have the problem of trying to call this function. Now,

77
00:05:21,100 --> 00:05:24,850
because this function was declared inside this function,

78
00:05:25,240 --> 00:05:30,240
its scope means that it's only accessible inside the confines of this function.

79
00:05:31,630 --> 00:05:34,750
So if we were to go outside of the function, so by

80
00:05:34,750 --> 00:05:39,400
indenting back to the beginning and we try to call this nested function,

81
00:05:39,730 --> 00:05:42,490
then it's actually not going to work.

82
00:05:42,910 --> 00:05:47,410
We're going to get a name error. It's not defined. However,

83
00:05:47,410 --> 00:05:52,410
if we call this function inside this outer_function,

84
00:05:53,680 --> 00:05:57,070
then it will now no longer generate an error.

85
00:05:57,920 --> 00:06:02,920
So let's go ahead and trigger the outer_function by calling it in our main.

86
00:06:04,670 --> 00:06:09,320
py. And when I run this, you can see it says I'm outer

87
00:06:09,770 --> 00:06:11,270
and then it says I'm inner.

88
00:06:12,170 --> 00:06:17,170
So this first gets executed and then this. And this I'm inner is being

89
00:06:17,300 --> 00:06:21,650
printed when this line is being evaluated. Now,

90
00:06:22,250 --> 00:06:27,250
one of the other things you could do is you can actually return a function from

91
00:06:28,280 --> 00:06:29,150
another function.

92
00:06:29,380 --> 00:06:30,213
Right.

93
00:06:32,050 --> 00:06:35,920
Functions can actually be returned from other functions.

94
00:06:36,370 --> 00:06:41,370
So if I make a copy of this previous function right here and comment out this

95
00:06:42,430 --> 00:06:45,850
other function and all the steps before,

96
00:06:46,330 --> 00:06:47,163
...

97
00:06:54,850 --> 00:06:57,430
and we only have this bit of active code,

98
00:06:57,850 --> 00:07:01,720
then you can see that instead of calling this nested_function here,

99
00:07:02,170 --> 00:07:04,540
I could also return it as the output.

100
00:07:05,050 --> 00:07:09,490
But the important part here is I'm going to get rid of the parentheses

101
00:07:09,610 --> 00:07:13,720
which means I'm no longer activating that function right here.

102
00:07:14,560 --> 00:07:17,440
So now when I call this outer_function,

103
00:07:17,830 --> 00:07:22,830
the output that this line is going to evaluate to is going to become the nested_

104
00:07:23,770 --> 00:07:28,390
function. So you could almost store it inside a variable.

105
00:07:28,480 --> 00:07:31,570
So let's say I create a variable called inner_function

106
00:07:31,900 --> 00:07:34,840
which is equal to the output of the outer_function

107
00:07:34,870 --> 00:07:39,100
which is basically this nested_function that's being returned. Well

108
00:07:39,100 --> 00:07:41,890
then, not only can I trigger the outer_function

109
00:07:42,100 --> 00:07:44,950
which is just going to give me I'm outer,

110
00:07:45,490 --> 00:07:50,490
now I can also trigger the inner_function separately by calling it

111
00:07:51,100 --> 00:07:54,610
and then adding the activator which is the parentheses.

112
00:07:55,900 --> 00:07:59,470
So now it says I'm outer after it evaluates this line,

113
00:07:59,830 --> 00:08:03,070
I'm inner after it evaluates this line. Now,

114
00:08:03,100 --> 00:08:04,900
if this is confusing to you,

115
00:08:04,960 --> 00:08:09,400
I recommend heading over to the course resources where I've got a link to this

116
00:08:09,490 --> 00:08:14,350
Python Tutor where I've entered all the code that we've seen just now

117
00:08:14,830 --> 00:08:17,800
and we can execute this code line by line.

118
00:08:18,340 --> 00:08:22,390
So you can see that the first thing that happens is it looks at this outer_

119
00:08:22,390 --> 00:08:26,740
function and it creates a reference to that function. Now

120
00:08:26,740 --> 00:08:31,740
next, it's on this line where our outer_function is actually being executed

121
00:08:32,650 --> 00:08:34,780
because it has the parentheses at the end.

122
00:08:35,169 --> 00:08:39,370
So now it's actually going to go inside this outer function and go through it

123
00:08:39,370 --> 00:08:44,370
line by line where it prints I'm outer and then sets up a reference to this second

124
00:08:45,610 --> 00:08:48,400
function, which is the nested_function.

125
00:08:49,270 --> 00:08:52,840
The nested_function can now be called by its name

126
00:08:52,840 --> 00:08:57,180
which is nested_function. But the very end of the outer_function,

127
00:08:57,300 --> 00:09:01,830
that function is going to be the return value. So it's going to be outputted.

128
00:09:02,640 --> 00:09:03,390
Finally,

129
00:09:03,390 --> 00:09:08,390
we get to the end of this line nine and we set up a reference from this variable

130
00:09:09,570 --> 00:09:14,400
called inner_function to this nested_function. And finally,

131
00:09:14,400 --> 00:09:18,120
when we get to the line 10 we trigger that function.

132
00:09:18,210 --> 00:09:22,560
So here is our inner_function which points to this nested function

133
00:09:22,860 --> 00:09:24,930
and so when we trigger this inner_function,

134
00:09:25,230 --> 00:09:28,440
it's the same as triggering the nested_function.

135
00:09:28,800 --> 00:09:32,520
And that is when we end up going into this function

136
00:09:32,820 --> 00:09:35,190
and printing out what it says inside.

137
00:09:35,820 --> 00:09:40,320
Have a play around with that to fully get to grips with all the things that you

138
00:09:40,320 --> 00:09:41,760
can do with a function.

139
00:09:42,930 --> 00:09:47,490
And once you're happy with all of this and you've reviewed it and you understand

140
00:09:47,490 --> 00:09:48,630
everything that's going on,

141
00:09:48,960 --> 00:09:52,800
then you've got the foundations to head over to the next lesson where we're

142
00:09:52,800 --> 00:09:55,620
going to talk about Python decorators.

