1
00:00:04,710 --> 00:00:06,809
Alright, so moving on now with the

2
00:00:06,809 --> 00:00:08,519
completion of the challenge introduced

3
00:00:08,519 --> 00:00:11,430
in the last video, it's now time to time

4
00:00:11,430 --> 00:00:13,260
the functions. So to start off doing that

5
00:00:13,260 --> 00:00:15,750
we need to firstly import the timeit

6
00:00:15,750 --> 00:00:18,480
module. Let's go ahead and do that -

7
00:00:18,480 --> 00:00:21,780
it should be on line 1, above the text

8
00:00:21,780 --> 00:00:23,420
definition. So it's going to be import

9
00:00:23,420 --> 00:00:26,640
timeit. Now as I said in

10
00:00:26,640 --> 00:00:28,650
the previous video, I'm going to do it

11
00:00:28,650 --> 00:00:30,690
slightly differently. So the challenge

12
00:00:30,690 --> 00:00:32,610
was to time the code, and if you've added

13
00:00:32,610 --> 00:00:34,109
code, something

14
00:00:34,109 --> 00:00:36,870
along the lines of this; so 

15
00:00:36,870 --> 00:00:40,170
something like print parentheses timeit

16
00:00:40,170 --> 00:00:43,820
dot timeit parentheses comp

17
00:00:43,820 --> 00:00:46,770
underscore caps parentheses double quote

18
00:00:46,770 --> 00:00:49,590
comma. Then do something like setup

19
00:00:49,590 --> 00:00:54,469
equals, double quotes again, from

20
00:00:54,469 --> 00:00:59,879
map underscore intro import comp underscore

21
00:00:59,879 --> 00:01:06,390
caps, then number equals 10,000,

22
00:01:06,390 --> 00:01:08,940
or actually make it 100,000. So if you did

23
00:01:08,940 --> 00:01:10,950
something like that, or put the functions

24
00:01:10,950 --> 00:01:12,840
inside the strings, then that's fine. You don't

25
00:01:12,840 --> 00:01:14,130
need to watch me do something that we've

26
00:01:14,130 --> 00:01:15,720
already covered, and we've looked at the

27
00:01:15,720 --> 00:01:17,460
various ways that you can provide the

28
00:01:17,460 --> 00:01:19,830
correct environment to timeit. However,

29
00:01:19,830 --> 00:01:21,600
there is another method we can use,

30
00:01:21,600 --> 00:01:23,820
and you have to read the documentation very

31
00:01:23,820 --> 00:01:26,700
carefully to work it out. So let's have a

32
00:01:26,700 --> 00:01:28,080
look at the documentation and you'll see

33
00:01:28,080 --> 00:01:30,090
what I mean. So we'll just bring it up in

34
00:01:30,090 --> 00:01:36,000
a browser. The bit I'm interested in is down

35
00:01:36,000 --> 00:01:37,350
here, under 28.2.2,

36
00:01:37,350 --> 00:01:40,740
Python Interface. Now in the

37
00:01:40,740 --> 00:01:43,470
description of timeit, it says that this

38
00:01:43,470 --> 00:01:45,750
method will create a timer instance with

39
00:01:45,750 --> 00:01:48,090
the given argument, setup code and timer

40
00:01:48,090 --> 00:01:50,610
function, and run its timeit parenthesis

41
00:01:50,610 --> 00:01:52,799
method. Now these three functions are

42
00:01:52,799 --> 00:01:55,110
convenience functions, to save us from

43
00:01:55,110 --> 00:01:56,670
having to type, or create rather,

44
00:01:56,670 --> 00:01:59,340
instances of the timeit class. That's

45
00:01:59,340 --> 00:02:01,049
the three there that you can see, one two

46
00:02:01,049 --> 00:02:03,540
three. Now as you can see, the

47
00:02:03,540 --> 00:02:06,060
documentation is quite sparse. If you

48
00:02:06,060 --> 00:02:07,649
want to know more, we should look at

49
00:02:07,649 --> 00:02:09,329
that timer class which you can see down here,

50
00:02:09,329 --> 00:02:11,599
immediately below those functions.

51
00:02:11,599 --> 00:02:14,249
And there you'll find a more detailed

52
00:02:14,249 --> 00:02:16,439
description of what the convenience

53
00:02:16,439 --> 00:02:18,360
functions are doing for us and

54
00:02:18,360 --> 00:02:19,710
it's worth reading the timer class

55
00:02:19,710 --> 00:02:22,440
documentation carefully. Now if we scroll

56
00:02:22,440 --> 00:02:24,930
down and have a look, the last paragraph for

57
00:02:24,930 --> 00:02:26,190
the class itself, just before the

58
00:02:26,190 --> 00:02:27,600
description of the timeit method down

59
00:02:27,600 --> 00:02:29,550
here, is interesting because it says

60
00:02:29,550 --> 00:02:32,040
that the statement and setup parameters can

61
00:02:32,040 --> 00:02:33,810
also take objects that are callable

62
00:02:33,810 --> 00:02:36,660
without arguments. Objects that are

63
00:02:36,660 --> 00:02:39,690
callable, basically, mean functions. There

64
00:02:39,690 --> 00:02:41,430
are other callable objects in Python,

65
00:02:41,430 --> 00:02:43,500
classes for example, and they're called

66
00:02:43,500 --> 00:02:45,990
to create a class instance. Alright so

67
00:02:45,990 --> 00:02:48,150
what that sentence means is that we can

68
00:02:48,150 --> 00:02:50,190
pass a reference to a function

69
00:02:50,190 --> 00:02:53,490
as the statement to be timed. The function

70
00:02:53,490 --> 00:02:55,110
must not have any parameters,

71
00:02:55,110 --> 00:02:56,550
which becomes obvious when you see the code,

72
00:02:56,550 --> 00:02:58,290
because there's no way to include

73
00:02:58,290 --> 00:03:01,380
arguments in a function reference. Now

74
00:03:01,380 --> 00:03:02,520
that'll make more sense when you've seen

75
00:03:02,520 --> 00:03:04,530
the code. So what I'm going to do is go back to

76
00:03:04,530 --> 00:03:07,080
IntelliJ. Now we'll just run this to make

77
00:03:07,080 --> 00:03:09,270
sure that it would have worked. You

78
00:03:09,270 --> 00:03:10,920
can see we did get a timing result there, so

79
00:03:10,920 --> 00:03:12,840
that's working. But for now what I'll do

80
00:03:12,840 --> 00:03:16,380
is, I'll comment that out. We're going to

81
00:03:16,380 --> 00:03:19,620
replace it by adding the code

82
00:03:19,620 --> 00:03:23,370
to timeout for functions. So I'll start off

83
00:03:23,370 --> 00:03:26,370
with print, then it's going to be

84
00:03:26,370 --> 00:03:29,670
parentheses timeit dot timeit. Then we're

85
00:03:29,670 --> 00:03:33,110
going to do comp underscore caps comma

86
00:03:33,110 --> 00:03:37,320
space number equals 100,000 and then the

87
00:03:37,320 --> 00:03:39,630
two closing parentheses. I'm going to

88
00:03:39,630 --> 00:03:43,620
take a copy of that line, and we'll actually

89
00:03:43,620 --> 00:03:45,090
call the other functions as well. So I've

90
00:03:45,090 --> 00:03:47,660
got comp underscore caps. The second one

91
00:03:47,660 --> 00:03:52,290
will be map underscore caps, the third

92
00:03:52,290 --> 00:03:57,540
one is comp underscore words and the

93
00:03:57,540 --> 00:04:03,480
last one will be map underscore words. So

94
00:04:03,480 --> 00:04:05,400
you can see that's a lot simpler. There's

95
00:04:05,400 --> 00:04:07,200
no setup argument needed for one thing,

96
00:04:07,200 --> 00:04:08,880
when you pass a function reference to

97
00:04:08,880 --> 00:04:11,489
timeit. In fact it looks suspiciously

98
00:04:11,489 --> 00:04:14,400
easy. So the real question here is,

99
00:04:14,400 --> 00:04:18,988
does it work? Let's run the program,

100
00:04:18,988 --> 00:04:20,970
and then you can see the timings there for our

101
00:04:20,970 --> 00:04:22,370
four functions, so clearly it's working.

102
00:04:22,370 --> 00:04:24,870
Now before we go into detail and look at

103
00:04:24,870 --> 00:04:26,760
those times, let's review what we did

104
00:04:26,760 --> 00:04:28,680
here. So we wrapped each of our code

105
00:04:28,680 --> 00:04:31,530
blocks up in a function definition. You

106
00:04:31,530 --> 00:04:32,340
either have to do that,

107
00:04:32,340 --> 00:04:34,889
or turn them into a string in order to

108
00:04:34,889 --> 00:04:37,290
time them. Next we passed a reference to

109
00:04:37,290 --> 00:04:39,720
each of the functions, to the timeit dot timeit

110
00:04:39,720 --> 00:04:41,850
function. Note that again, we're not

111
00:04:41,850 --> 00:04:43,800
using parentheses. We're passing a

112
00:04:43,800 --> 00:04:46,199
reference to the function, not a function

113
00:04:46,199 --> 00:04:48,690
call. Now if you try to call the function,

114
00:04:48,690 --> 00:04:51,330
you'll get an error. So if we replace

115
00:04:51,330 --> 00:04:53,130
the first reference there - the comp underscore

116
00:04:53,130 --> 00:04:56,280
caps - and add parentheses, try and

117
00:04:56,280 --> 00:04:58,770
run that, you'll get an error. And that's

118
00:04:58,770 --> 00:05:00,540
because when the documentation refers

119
00:05:00,540 --> 00:05:02,990
to a callable, it means the function itself

120
00:05:02,990 --> 00:05:05,660
not the result of calling the function.

121
00:05:05,660 --> 00:05:08,700
There are other ways to use timeit

122
00:05:08,700 --> 00:05:10,590
and now you know how it works, try Googling

123
00:05:10,590 --> 00:05:12,479
for other examples. We'll come back to

124
00:05:12,479 --> 00:05:14,160
this later when we've looked at

125
00:05:14,160 --> 00:05:16,080
decorators. For now, I'm going to remove

126
00:05:16,080 --> 00:05:18,810
the bogus parentheses and run the

127
00:05:18,810 --> 00:05:21,000
program again, so that we can review

128
00:05:21,000 --> 00:05:22,260
those timings in the bottom left hand

129
00:05:22,260 --> 00:05:24,600
corner of the screen. There's not a great

130
00:05:24,600 --> 00:05:26,550
deal of difference, but after running the

131
00:05:26,550 --> 00:05:30,150
program a few times, you can see that

132
00:05:30,150 --> 00:05:32,039
after running the program a few times,

133
00:05:32,039 --> 00:05:34,650
as I'm doing now, there's not really a great

134
00:05:34,650 --> 00:05:35,550
deal of difference but the

135
00:05:35,550 --> 00:05:37,800
comprehensions appear to be slightly

136
00:05:37,800 --> 00:05:40,860
faster than using a map. Now it's

137
00:05:40,860 --> 00:05:42,389
interesting because when I actually ran

138
00:05:42,389 --> 00:05:45,750
this on my iMac Pro, which has got many

139
00:05:45,750 --> 00:05:48,720
cores, the first time that function - the

140
00:05:48,720 --> 00:05:50,729
map underscore, the map underscore

141
00:05:50,729 --> 00:05:53,370
caps function - appeared to be faster. But

142
00:05:53,370 --> 00:05:54,990
as you can see here on this Mac, and most

143
00:05:54,990 --> 00:05:57,090
probably on most computers that you run

144
00:05:57,090 --> 00:05:58,770
this, you should find that comprehensions

145
00:05:58,770 --> 00:06:01,260
version is slightly faster. So in other

146
00:06:01,260 --> 00:06:02,400
words, the comp_caps

147
00:06:02,400 --> 00:06:04,380
function and the comp underscore

148
00:06:04,380 --> 00:06:05,820
words function should generally

149
00:06:05,820 --> 00:06:07,169
be faster for you, and you can see that's

150
00:06:07,169 --> 00:06:08,550
the case, in the code that I'm executing

151
00:06:08,550 --> 00:06:10,440
here because I'm on a different Mac

152
00:06:10,440 --> 00:06:13,440
computer now. So I'll run that again. You

153
00:06:13,440 --> 00:06:15,150
can see, we're consistently finding that the

154
00:06:15,150 --> 00:06:17,310
comprehensions version is slightly

155
00:06:17,310 --> 00:06:21,450
faster than the map version. The timing

156
00:06:21,450 --> 00:06:23,190
for the comprehension is the first value

157
00:06:23,190 --> 00:06:25,080
in each pair, and the value for

158
00:06:25,080 --> 00:06:26,880
com underscore caps and map underscore

159
00:06:26,880 --> 00:06:28,950
caps, the first pair of timings was

160
00:06:28,950 --> 00:06:31,289
pretty inconclusive, when we tried to run

161
00:06:31,289 --> 00:06:33,169
it on a 16 gigabyte Linux system.

162
00:06:33,169 --> 00:06:34,740
Capitalizing the words is more

163
00:06:34,740 --> 00:06:36,150
consistent, though, with the comprehension

164
00:06:36,150 --> 00:06:38,550
working out slightly faster, but you can

165
00:06:38,550 --> 00:06:40,289
see in my case here though, in both

166
00:06:40,289 --> 00:06:41,580
scenarios I've run this a number of

167
00:06:41,580 --> 00:06:43,500
times, even though the results are close,

168
00:06:43,500 --> 00:06:45,690
on every single occasion we're finding the

169
00:06:45,690 --> 00:06:46,169
comprehension

170
00:06:46,169 --> 00:06:49,259
version is beating out the map version.

171
00:06:49,259 --> 00:06:51,599
In other words, it's faster.  If you come

172
00:06:51,599 --> 00:06:53,129
across map being used in code that you

173
00:06:53,129 --> 00:06:54,449
have to work with, you now know what

174
00:06:54,449 --> 00:06:56,340
it's doing. When running your own code,

175
00:06:56,340 --> 00:06:58,379
there's little reason to use a map,

176
00:06:58,379 --> 00:07:00,629
though, instead of a comprehension. So

177
00:07:00,629 --> 00:07:02,099
I'm going to stop the video here, and in

178
00:07:02,099 --> 00:07:03,270
the next one we'll start looking at the

179
00:07:03,270 --> 00:07:05,879
filter function. So I'll see you in the

180
00:07:05,879 --> 00:07:08,330
next video.

