1
00:00:05,500 --> 00:00:10,670
Alright, so I stopped the last video with a challenge. That was to work out which of our two factorial functions

2
00:00:11,030 --> 00:00:12,050
performed better.

3
00:00:12,070 --> 00:00:17,720
Now, both functions take an argument. That means that we can't pass them directly to the timeit function.

4
00:00:17,720 --> 00:00:19,320
Now we'll see a way around that,

5
00:00:19,430 --> 00:00:20,930
when we've looked at decorators.

6
00:00:21,040 --> 00:00:23,630
For now though, we have to test calling the functions.

7
00:00:23,870 --> 00:00:27,190
So let's actually make sure they work first, by calling each one.

8
00:00:27,470 --> 00:00:32,119
So we'll add these four lines to the end of the program, remembering that we need to add two

9
00:00:32,119 --> 00:00:35,030
blank lines after the function definitions.

10
00:00:35,180 --> 00:00:39,190
So I'm going to start with x equals fact(

11
00:00:39,600 --> 00:00:50,700
130)  print(x). Then we're going to do y equals factorial(130)  print(y).

12
00:00:51,890 --> 00:00:58,320
OK so we'll run that. You can see that each one there has produced the same result, as we would expect it to have

13
00:00:58,320 --> 00:00:59,130
done.

14
00:00:59,610 --> 00:01:00,240
So that's fine.

15
00:01:03,750 --> 00:01:06,220
Just fix up that little warning there.

16
00:01:06,280 --> 00:01:12,490
So it's those function calls, on lines 30 and 32, that we want to test.

17
00:01:12,490 --> 00:01:14,230
Now there's a few ways to do this.

18
00:01:14,260 --> 00:01:17,950
Remember that we need to make sure, or make the functions available to timeit

19
00:01:18,130 --> 00:01:24,280
by using the setup argument. And if you're using Python 3.5 or above, you may have used globals

20
00:01:24,280 --> 00:01:24,800
instead.

21
00:01:24,850 --> 00:01:26,200
So either way is fine.

22
00:01:26,200 --> 00:01:32,260
So one easy way, is to move the function calls to just after each function, then wrap the whole lot up

23
00:01:32,290 --> 00:01:33,460
in a string.

24
00:01:33,670 --> 00:01:40,030
So what I can do is just come back here, to the x = fact(130) and I can print that and or add that, rather,

25
00:01:40,660 --> 00:01:49,780
on line 21. And I can come back up here and put fact_test equals three double quotes

26
00:01:50,530 --> 00:01:56,390
backslash, and take those last three double quotes, and paste them under the x = fact

27
00:01:56,710 --> 00:01:59,160
line - this line here, line number 22.

28
00:01:59,410 --> 00:02:09,180
And then for the next one, we can take the y = factorial line. Add that, with a space, and come back

29
00:02:09,240 --> 00:02:12,700
and define the second string,

30
00:02:13,220 --> 00:02:17,030
factorial_test is equal to three double quotes

31
00:02:17,040 --> 00:02:23,080
and a backslash. Take the last three double quotes, and paste them under the y = factorial line, like

32
00:02:23,710 --> 00:02:26,800
so. Let's remove these other lines.

33
00:02:26,830 --> 00:02:31,720
The prints, we don't need at the moment. And what we can now do is call the timeit function with each string.

34
00:02:31,980 --> 00:02:38,300
So we can start by print parentheses, and it's going to be timeit

35
00:02:38,520 --> 00:02:43,700
dot timeit parentheses and that's going to be fact_test,

36
00:02:43,830 --> 00:02:49,570
comma and we'll do number equals 10000.

37
00:02:49,720 --> 00:02:50,480
That's the first one.

38
00:02:50,500 --> 00:02:54,120
And then we'll just duplicate that line and for the second test,

39
00:02:54,160 --> 00:02:55,570
it's going to be factorial_test,

40
00:02:58,220 --> 00:03:00,930
factorial_test.

41
00:03:00,940 --> 00:03:02,770
Now obviously, there was a few ways to do this,

42
00:03:02,770 --> 00:03:05,000
as I said. Let's now run the program

43
00:03:08,420 --> 00:03:13,620
and you can see there in the second test, the recursive function takes over twice as long to run,

44
00:03:13,910 --> 00:03:21,660
and depending on how many times you run it, maybe even more than that. Over double, there.

45
00:03:21,800 --> 00:03:26,740
So there's a few ways to do this, as I said, but if you managed to time the functions correctly, then well done!

46
00:03:26,790 --> 00:03:30,570
Now I'd probably have done this a little bit differently.

47
00:03:30,650 --> 00:03:35,570
Now we've covered everything we need to use this next approach, but putting it all together may not have

48
00:03:35,570 --> 00:03:36,920
been obvious.

49
00:03:36,950 --> 00:03:43,280
Now the setup string can be an import, and we can import our own module, as long as we make sure the

50
00:03:43,280 --> 00:03:45,410
timeit code isn't executed.

51
00:03:45,460 --> 00:03:50,870
Now to see what I mean, I'm going to undo all these changes, going all the way back to having just these function

52
00:03:50,870 --> 00:03:52,120
definitions.

53
00:03:52,400 --> 00:03:55,520
I'm going to close this down, and I'm just going to undo everything.

54
00:04:02,010 --> 00:04:04,350
I'll just add the last blank line at the end there.

55
00:04:04,990 --> 00:04:11,330
So our module can actually be imported, but we have to make sure that any code we add isn't executed.

56
00:04:11,470 --> 00:04:14,950
Remember that we do this by checking the value of underscore underscore name_ underscore underscore

57
00:04:14,950 --> 00:04:22,970
So I can put some extra code down here, on line 30, and I can type if __name__

58
00:04:23,580 --> 00:04:28,850
equals "__main__"

59
00:04:28,900 --> 00:04:33,440
colon.

60
00:04:33,670 --> 00:04:36,010
Then we can do print parentheses

61
00:04:36,200 --> 00:04:36,890
timeit dot

62
00:04:36,930 --> 00:04:43,360
timeit and double quotes x equals fact(130) in double

63
00:04:43,680 --> 00:04:51,960
quotes as you can see there, comma setup equals double quotes from space

64
00:04:51,960 --> 00:04:57,190
__main__ import fact

65
00:04:59,160 --> 00:04:59,530
comma

66
00:04:59,530 --> 00:05:03,200
then number equals 10000.

67
00:05:03,460 --> 00:05:12,520
That's the first line. And I can ducplicate that line, and we'll change the second one to factorial(130)

68
00:05:12,630 --> 00:05:19,970
setup is from __main__ import, and this time it's import factorial.

69
00:05:20,350 --> 00:05:24,850
So the code's only going to be executed if our program's run as a script.

70
00:05:24,850 --> 00:05:27,660
So in other words, it won't be executed when the module is imported.

71
00:05:27,670 --> 00:05:28,790
So if you run the program now

72
00:05:32,000 --> 00:05:33,630
you can see we're still getting the output there.

73
00:05:33,920 --> 00:05:39,380
So it's probably not obvious that you can import from main as we have done here, from __main__

74
00:05:39,380 --> 00:05:48,530
So that's equivalent of from, we could have done timeitchallenge import fact. That would also work, but the advantage

75
00:05:48,530 --> 00:05:54,240
of using the __main__ is that it will still work even if we rename the file.

76
00:05:54,290 --> 00:05:57,450
I'll just undo those changes, and put it back to main.

77
00:05:57,470 --> 00:06:00,390
So this approach needed fewer changes to our code.

78
00:06:00,460 --> 00:06:06,600
It gives similar capabilities to using globals, and also works on Python 3.4 and earlier.

79
00:06:06,800 --> 00:06:12,730
Now if you read the documentation for timeit - we'll get back to our Web site -

80
00:06:12,950 --> 00:06:16,040
you'll actually see this being used right at the bottom of the page.

81
00:06:16,170 --> 00:06:21,400
It has setup equals __main__ import test.

82
00:06:21,400 --> 00:06:22,990
Alright so that's the end of the challenge.

83
00:06:22,990 --> 00:06:27,730
But I also promised you, in the last video, to show you how to use repeat instead of timeit.

84
00:06:27,960 --> 00:06:33,470
Now it's very similar, but it runs the test several times, and returns a list of all the individual timings.

85
00:06:33,850 --> 00:06:35,550
So let's go back and have a look at that.

86
00:06:38,540 --> 00:06:42,200
Alright, so I've undone that change there, so we're looking back at main again now.

87
00:06:42,240 --> 00:06:45,780
So I'm going to then change our code to use timeit.

88
00:06:45,800 --> 00:06:50,460
Instead of timeit.timeit, it's timeit.repeat.

89
00:06:51,080 --> 00:06:54,780
We can use that for both calls, and run that.

90
00:06:57,660 --> 00:07:00,070
You can see we get two lists printed out there.

91
00:07:00,460 --> 00:07:03,290
Each one contains the timeit results for three runs.

92
00:07:03,460 --> 00:07:07,570
And that's because they repeat, or repeat defaults to repeating the test three times.

93
00:07:07,570 --> 00:07:10,200
But you can also override that and change that if you want.

94
00:07:10,240 --> 00:07:21,760
So I can come down here and put repeat=6, for argument's sake, repeat equals six. And the same for the next one, equals six.

95
00:07:22,010 --> 00:07:22,600
And run that again.

96
00:07:26,580 --> 00:07:31,220
And you can see we've got our two lists this time, with the timeit results for six results

97
00:07:31,220 --> 00:07:32,510
in each list.

98
00:07:32,570 --> 00:07:37,250
Now this is one reason for the warning about not performing statistical analysis on the results, by the

99
00:07:37,250 --> 00:07:40,210
way. When you've got a set of values in a list,

100
00:07:40,280 --> 00:07:43,510
it's very easy to calculate things like the average.

101
00:07:43,580 --> 00:07:47,070
So let's go ahead and change the code a little bit more.

102
00:07:47,120 --> 00:07:51,630
We're going to assign the lists of variables instead of just printing them, and have a look at doing that.

103
00:07:52,000 --> 00:07:59,690
So instead of print, we're going to put list1 equals, get rid of the initial parentheses and the ending

104
00:07:59,690 --> 00:08:06,560
one. Then list 2 equals - the same thing about removing the parentheses,

105
00:08:06,980 --> 00:08:17,770
and then we're going to do print(sum(list1)) and print(sum(list2)).

106
00:08:18,900 --> 00:08:22,640
So the sum function calculates the sum of the values in a list.

107
00:08:22,860 --> 00:08:29,480
Let's try running that. OK so you can see that it works nicely. In this case, you can see that the

108
00:08:29,480 --> 00:08:35,030
sum function calculates the sum of the values in the list, and you could get the arithmetic mean by dividing

109
00:08:35,030 --> 00:08:37,340
by the number of items in the list.

110
00:08:37,370 --> 00:08:42,799
But note also there's a statistics module, in the standard library for Python 3, and we can actually import

111
00:08:42,799 --> 00:08:44,730
that to analyze the results further.

112
00:08:44,930 --> 00:08:46,410
Let's have a go at doing that.

113
00:08:46,470 --> 00:08:53,030
So we're going to come back up to the top of the code, and put another line, line 12; from statistics

114
00:08:55,490 --> 00:09:01,190
import mean comma stdev - standard deviation.

115
00:09:01,360 --> 00:09:11,200
And I can come down here, to our output, and we can do something like, change this first one to mean, list1 and we'll also

116
00:09:11,200 --> 00:09:12,040
do a comma

117
00:09:12,170 --> 00:09:15,340
stdev(list1).

118
00:09:15,350 --> 00:09:17,690
We can do the same for list2.

119
00:09:18,160 --> 00:09:23,500
So mean(list2), stdev(list2).

120
00:09:27,780 --> 00:09:29,560
Alright, we'll run this to check it works.

121
00:09:30,960 --> 00:09:35,630
And you can see now that we're getting the mean and standard deviation for each list.

122
00:09:35,630 --> 00:09:40,410
Now if you're not into statistics, then you probably wouldn't have dreamt of doing it that way anyway.

123
00:09:40,610 --> 00:09:46,010
But if you are into statistics, that note in the documentation is for you. Statistical analysis like

124
00:09:46,010 --> 00:09:52,460
this is only useful if you're able to account for all the variables, and there's so many other factors

125
00:09:52,460 --> 00:09:58,400
causing variations in the timings on a multi-tasking operating system, that the mean and standard deviation

126
00:09:58,670 --> 00:10:00,490
are effectively meaningless.

127
00:10:00,500 --> 00:10:02,060
So use common sense instead.

128
00:10:02,300 --> 00:10:06,920
But that was a good excuse to show you sum of the statistics functions, anyway. Now you can find

129
00:10:06,920 --> 00:10:12,890
out more information on the statistics functions that are available, and how to use them, in the documentation

130
00:10:13,400 --> 00:10:22,880
that Python have put together - the Python crowd. and I'll put the link there for you to check out some time, at your leisure.

131
00:10:22,880 --> 00:10:27,500
Alright, so we've covered a few different ways to use timeit module in these last few videos.

132
00:10:27,530 --> 00:10:32,920
Now I haven't yet looked at the Timer class, but using it's no harder than using the timeit and repeat helper

133
00:10:32,930 --> 00:10:34,070
functions.

134
00:10:34,100 --> 00:10:39,500
The tricky bit is the setup and globals arguments, and you should now be confident in setting up the environment

135
00:10:39,500 --> 00:10:42,680
correctly, so that you can run your tests. In the next video,

136
00:10:42,680 --> 00:10:47,390
what we're going to do is go back to comprehensions, and look at some of the alternative functions that

137
00:10:47,390 --> 00:10:48,860
Python provides.

138
00:10:48,890 --> 00:10:50,030
So I'll see you in the next video.

