WEBVTT

0
00:00.390 --> 00:03.780
In this lesson, we're going to talk about errors and exceptions.

1
00:04.170 --> 00:06.810
I'll show you what happens when a program encounters

2
00:06.840 --> 00:10.980
different types of errors and how you can write code to handle these situations.

3
00:12.060 --> 00:15.810
To begin, I've created a brand new project called day-30

4
00:16.020 --> 00:20.760
and I've created my main.py file. Now notice how inside my project,

5
00:20.790 --> 00:24.990
there is only one code file at the moment. There is no data files,

6
00:24.990 --> 00:28.140
no text files, nothing. In this situation

7
00:28.170 --> 00:33.170
if I was to try and open up a particular file that doesn't exist and I tried to

8
00:33.330 --> 00:35.100
read it, what do you think would happen?

9
00:35.670 --> 00:38.610
So we're going to use our normal syntax with open,

10
00:38.910 --> 00:42.480
and let's just make up a file name. So a_file.txt.

11
00:42.990 --> 00:45.360
And I'm going to save that as file

12
00:45.630 --> 00:50.630
and I'm going to take this file and try to read from it. Right now

13
00:51.120 --> 00:55.710
if I run this code, then this is what happens.

14
00:56.100 --> 00:59.520
I get a trace back and I get a error

15
00:59.550 --> 01:03.570
which is the file not found error, which kind of makes sense

16
01:03.570 --> 01:08.570
given that there really is no such file existing inside our folder where we're

17
01:08.820 --> 01:11.520
telling it to search. That's not great.

18
01:11.820 --> 01:15.900
And if this happens somewhere within our actual program, so here

19
01:15.900 --> 01:20.100
I've got the password manager completed project from yesterday.

20
01:20.640 --> 01:24.840
If in this case, I made a typo in this word

21
01:24.870 --> 01:29.190
so instead of data.txt, I wrote daata.txt.

22
01:29.850 --> 01:34.170
And instead of the append mode, I had the read mode. Well,

23
01:34.170 --> 01:37.500
in this case, what would happen is exactly the same thing.

24
01:37.500 --> 01:40.530
So I could have a website, have a password,

25
01:40.680 --> 01:44.400
but as soon as I hit add, then we get our file

26
01:44.400 --> 01:48.510
not found error. And notice how as soon as that error happens,

27
01:48.840 --> 01:52.620
it actually doesn't continue because on the next few lines,

28
01:52.650 --> 01:54.480
we've actually got these two lines of code

29
01:54.780 --> 01:59.490
which deletes the entry inside the website entry and also the password entry.

30
01:59.610 --> 02:04.200
But those lines of code are not being carried out because it's hit a stumbling

31
02:04.200 --> 02:04.830
block.

32
02:04.830 --> 02:09.390
It has not found the file that we're trying to open and we're trying to read.

33
02:10.080 --> 02:12.630
So I'm going to restore the code to how it was previously,

34
02:12.990 --> 02:16.950
but this is a good point to start thinking about errors because we've come

35
02:16.950 --> 02:21.450
across a lot of errors, right? Including errors like key error.

36
02:22.710 --> 02:23.730
So for example,

37
02:23.730 --> 02:28.730
if we have a dictionary that has just one key-value pair and we somehow try to

38
02:29.280 --> 02:31.620
get a value from that dictionary

39
02:31.860 --> 02:34.830
by tapping into a key that doesn't exist,

40
02:36.660 --> 02:40.890
then when we run this code, we will get a key error, right?

41
02:41.070 --> 02:45.600
It can't actually pick out the value from this dictionary because this key that

42
02:45.600 --> 02:49.740
we provided does not exist in that dictionary. Now,

43
02:49.770 --> 02:53.550
some of the other popular ones that you've seen are the index error.

44
02:54.690 --> 02:55.620
So in this case

45
02:55.620 --> 03:00.620
we have a list and we basically are trying to get hold of an item from this list

46
03:02.230 --> 03:06.880
at an index that doesn't exist. So remember the index starts at 0, 1,

47
03:06.880 --> 03:11.110
2, and 3. There is nothing at 3. So again, when I run this,

48
03:11.170 --> 03:14.110
we get an error and this is an index error.

49
03:15.700 --> 03:20.200
And the final error that we've probably been used to seeing is the type error

50
03:20.500 --> 03:23.800
where we're trying to do something with a particular piece of data,

51
03:24.130 --> 03:27.550
but we cannot do that thing with a particular data type.

52
03:28.150 --> 03:30.580
Let's say we have a piece of text abc

53
03:30.760 --> 03:35.550
and we try to print it this text plus the number five,

54
03:35.760 --> 03:39.870
so a string plus an integer. And again,

55
03:39.870 --> 03:42.300
when I hit run it, again we get a type error.

56
03:43.110 --> 03:47.250
All of these types of errors we've actually come across already and

57
03:47.310 --> 03:48.600
all that we've done so far is

58
03:48.960 --> 03:53.460
we've just used it as an indicator to tell us, wait a minute,

59
03:53.460 --> 03:56.640
something's not quite right. We got to go and fix our code.

60
03:57.270 --> 03:59.760
But life doesn't really work out

61
03:59.760 --> 04:04.680
so neatly most of the time. In a lot of cases, it actually follows Morphy's law

62
04:04.980 --> 04:09.300
which states that anything that can go wrong probably will, eventually at some

63
04:09.300 --> 04:10.410
point, go wrong.

64
04:10.800 --> 04:15.210
So we have to plan for these eventualities just as, you know,

65
04:15.210 --> 04:17.280
your car is probably not going to break down,

66
04:17.550 --> 04:22.550
but you need breakdown cover just in case that it does happen. In programming

67
04:23.310 --> 04:28.310
what we can do is we can catch these exceptions. When something goes wrong

68
04:28.410 --> 04:31.710
and in that moment we catch that exception,

69
04:31.980 --> 04:34.380
then it doesn't have to fail catastrophically.

70
04:34.890 --> 04:39.690
We can actually fail more gracefully or we can decide that something else should

71
04:39.690 --> 04:40.523
happen.

72
04:40.800 --> 04:45.060
Here's what the code looks like when we're dealing with these exceptions.

73
04:45.360 --> 04:48.120
We have try, except, else and finally.

74
04:48.120 --> 04:52.680
These are the four keywords that are really important when it comes to handling

75
04:52.680 --> 04:53.513
exceptions.

76
04:54.000 --> 04:59.000
Now the first keyword try comes for a block of code where you're executing

77
05:00.510 --> 05:03.210
something that might cause an exception.

78
05:03.570 --> 05:07.590
So basically you're trying to execute a piece of line. In most cases,

79
05:07.590 --> 05:10.980
it probably will work, but sometimes it just might not.

80
05:11.760 --> 05:15.060
Now the next step is to define the except block.

81
05:15.510 --> 05:19.170
So this is the block of code that you want the computer to execute

82
05:19.440 --> 05:21.060
if there were more was an exception.

83
05:21.090 --> 05:25.860
If something went catastrophically wrong and it was not the way that you

84
05:25.860 --> 05:29.730
expected it to go, then carry out this piece of code.

85
05:30.780 --> 05:35.130
Now the else keyword allows you to find some code to execute

86
05:35.400 --> 05:39.720
if there were no exceptions. If you tried this thing that might fail

87
05:39.930 --> 05:43.560
but actually it didn't fail. You succeeded and there were no problems.

88
05:43.800 --> 05:47.430
Well then, in this case, you're going to do whatever is inside the else block.

89
05:47.970 --> 05:50.520
And then finally, we have the finally keyword

90
05:50.850 --> 05:55.020
which basically is just the block of code to carry out

91
05:55.230 --> 05:59.870
no matter what happens. If this thing that you tried failed

92
05:59.900 --> 06:04.880
or if it succeeded, Honeybadger, I mean, finally doesn't actually care.

93
06:05.630 --> 06:08.870
So no matter what happens with trying this line of code,

94
06:09.140 --> 06:12.470
this finally block is always going to be executed

95
06:12.770 --> 06:17.750
and it's usually used for cleaning things up or tidying things up at the end of

96
06:17.960 --> 06:22.520
some sort of code execution. Let's take our file not found exception

97
06:22.610 --> 06:27.260
and let's see how we can make this a lot safer by catching that exception.

98
06:27.710 --> 06:32.710
The thing that we're going to try is to open up this file. Instead of using the

99
06:33.290 --> 06:34.370
with format,

100
06:34.400 --> 06:39.400
I'm actually just gonna straight up create a file and set it to open this

101
06:39.500 --> 06:42.470
particular file path. So a_file.txt.

102
06:43.010 --> 06:48.010
Now this is the line of code that can cause an error and it will cause an error

103
06:48.530 --> 06:52.700
in our case because we don't have a file called a_file.txt.

104
06:53.270 --> 06:57.620
So this line of code is going to go inside a try block.

105
06:58.040 --> 07:02.840
So let's indent that. So this is the line of code that we're going to try. Now,

106
07:02.840 --> 07:07.340
the next thing we'll define is the except block. Basically,

107
07:07.340 --> 07:10.220
once we've tried running this line of code,

108
07:10.610 --> 07:15.610
and if there was an exception that was thrown when we were running it like the

109
07:15.710 --> 07:19.340
type error or in this case, it would be a file not found error,

110
07:19.580 --> 07:22.310
well then, in that case, we're going to do something different.

111
07:22.310 --> 07:26.210
We're going to let's say print, there was an error.

112
07:27.530 --> 07:31.190
So now let's run this code and you can see straight away,

113
07:31.220 --> 07:34.430
there was an error because this file doesn't exist.

114
07:34.460 --> 07:38.810
So this failed and therefore this line of code was executed.

115
07:39.200 --> 07:42.680
It's almost a little bit like we have an if statement and the

116
07:42.680 --> 07:47.030
if statement is checking to see if something fails, well,

117
07:47.030 --> 07:50.900
in that case, this is where it looks to see what it should do next.

118
07:51.500 --> 07:55.310
Now just printing there was an error is kind of pointless.

119
07:55.520 --> 08:00.520
What we actually want to do is to make sure that we don't actually fail so that

120
08:01.220 --> 08:05.690
whatever happens, we succeed. So if there is a good alternative,

121
08:05.750 --> 08:08.930
then that's what we're going to put inside the except block.

122
08:09.530 --> 08:11.240
What we're going to do instead

123
08:11.420 --> 08:15.830
if this file doesn't exist and we can't open it is we're just simply going to

124
08:15.830 --> 08:18.440
create it. To create a new file,

125
08:18.650 --> 08:21.140
remember that you can open up the file

126
08:23.810 --> 08:28.810
and you can open it using the write mode because when you're inside write mode,

127
08:29.900 --> 08:33.920
then what this open method is going to do is it's going to try and find this

128
08:33.920 --> 08:36.380
file and open it. But if it doesn't exist,

129
08:36.410 --> 08:41.090
it's just going to create it. Right now if I run this code again,

130
08:41.120 --> 08:46.040
I want you to watch inside the day-30 folder because as soon as I hit run,

131
08:46.250 --> 08:51.250
you'll notice that a_file.txt gets created because we tried opening it.

132
08:51.650 --> 08:52.670
It didn't exist.

133
08:52.940 --> 08:57.940
So it went into the except block and it actually just went ahead and created this

134
08:58.050 --> 08:59.490
file from scratch.

135
08:59.820 --> 09:03.900
Now this file is of course completely empty because we haven't told it to do

136
09:03.900 --> 09:08.520
anything, but we could, in fact, get our file and write something to it.

137
09:09.600 --> 09:14.460
We can put all of that inside the except block if we want to. Now,

138
09:14.460 --> 09:19.460
one of the things that's giving us a warning here with the except keyword is if

139
09:19.560 --> 09:23.910
you hover over it, it tells you that this is too broad an exception clause.

140
09:24.360 --> 09:27.270
And according to the PEP 8 recommendations,

141
09:27.540 --> 09:30.510
it tells us you should never use a bare except

142
09:30.960 --> 09:34.320
and the reason for this is because when you have an except  clause,

143
09:34.680 --> 09:38.580
then it's actually going to ignore all errors. For example,

144
09:38.670 --> 09:39.870
if inside here

145
09:40.020 --> 09:43.740
let's say I decided to do something that was also going to create an error,

146
09:43.770 --> 09:45.480
but not the same kind of error.

147
09:46.110 --> 09:50.490
So now I have a dictionary with a key and a value,

148
09:50.850 --> 09:55.170
but let's say I tried to print some sort of value from that dictionary

149
09:55.590 --> 09:58.440
and I use a non-existent key.

150
09:58.890 --> 10:03.360
So you can see that this dictionary does not have a key that is named this

151
10:03.660 --> 10:07.410
so this line is going to actually give us a key error.

152
10:07.740 --> 10:10.830
But now, notice what happens when I hit run.

153
10:11.700 --> 10:14.460
Absolutely nothing. I don't get any errors.

154
10:14.670 --> 10:17.820
And the reason for this is because inside the try block

155
10:18.150 --> 10:23.150
it's first trying to open up this file and indeed that file exists.

156
10:23.550 --> 10:28.020
So it moves on to the next line. It creates a dictionary called a_dictionary

157
10:28.080 --> 10:32.430
and that it tries to get hold of this value with this key

158
10:32.430 --> 10:33.390
from that dictionary.

159
10:33.810 --> 10:37.500
Now this line actually fails and creates an exception,

160
10:37.830 --> 10:40.500
but that exception is caught right here

161
10:40.920 --> 10:45.360
and it simply tells it to go ahead and create a file called a_file.txt

162
10:45.630 --> 10:50.130
which it will go ahead and do. So this is not what we want at all.

163
10:50.910 --> 10:51.660
Instead,

164
10:51.660 --> 10:56.130
we want our exception to catch a specific situation.

165
10:56.460 --> 11:01.460
We want to say that in the exception that we have a file not found error,

166
11:01.950 --> 11:06.300
then this is what we want to do. And now if I run the code again,

167
11:06.360 --> 11:08.850
you can see when now getting that key error

168
11:08.910 --> 11:13.560
and it's telling us that this thing worked, so it didn't generate a file

169
11:13.560 --> 11:14.430
not found error.

170
11:14.730 --> 11:18.240
But the next thing that it tried when it tried to print this value,

171
11:18.390 --> 11:19.770
it got a key error.

172
11:21.150 --> 11:26.150
So we can actually have multiple exceptions. Instead of just except file

173
11:26.670 --> 11:30.960
not found I can also say except key error and in this case,

174
11:30.960 --> 11:35.850
I'm just going to print that key does not exist. Now, if I hit run,

175
11:36.150 --> 11:39.810
I get no errors, but I do catch that exception

176
11:40.170 --> 11:45.170
and I have this print statement executing. In addition to simply catching an

177
11:46.770 --> 11:48.060
exception using

178
11:48.060 --> 11:52.860
except, you can also get hold of the error message that would have normally

179
11:52.870 --> 11:56.290
printed had we not had the exception called.

180
11:56.650 --> 12:00.910
Normally, you would get key error and it would give you a message that tells you

181
12:00.910 --> 12:02.500
which key was the problem.

182
12:03.130 --> 12:07.810
If we catch our exception and we still want to get hold of that error message,

183
12:08.110 --> 12:08.943
then we can say

184
12:08.950 --> 12:13.150
except key error as error message.

185
12:13.660 --> 12:18.490
And this means we can get hold of the error message that was generated from this

186
12:18.490 --> 12:23.050
exception if it does occur. Instead of saying that key does not exist,

187
12:23.110 --> 12:28.110
we can now take this as an f-string and we can say, the key, and we pass in the

188
12:29.590 --> 12:30.820
error message right here.

189
12:31.270 --> 12:36.270
So now I hit run again and it tells me the key 'sdfsdf' does not exist,

190
12:37.300 --> 12:41.200
which is a lot more useful than simply saying the key does not exist.

191
12:41.950 --> 12:46.930
So you can try, you can catch exceptions, you can catch other exceptions,

192
12:47.230 --> 12:51.370
you can also get hold of the error message and use it when you catch the

193
12:51.370 --> 12:56.050
exception. Now, the next keyword we mentioned was the else keyword

194
12:56.620 --> 13:01.620
and this block of code is going to execute when the thing that you're trying all

195
13:01.840 --> 13:05.830
succeeds. So if it managed to open up the file,

196
13:05.830 --> 13:08.710
it managed to print this item from the dictionary

197
13:08.980 --> 13:13.150
and there were no exceptions that were thrown from this block of code,

198
13:13.210 --> 13:17.440
then it's going to jump to the else block. So what else do you want to do?

199
13:18.100 --> 13:21.940
Well, maybe I actually want to read from this file,

200
13:22.000 --> 13:23.860
so file.read,

201
13:24.310 --> 13:27.130
and we save this as our content.

202
13:27.850 --> 13:31.930
And then we go ahead and print our content. Now,

203
13:31.960 --> 13:34.960
remember, if this file doesn't actually exist,

204
13:35.080 --> 13:37.630
this else block is never going to be triggered.

205
13:37.990 --> 13:40.780
So if I go ahead and simply delete this file

206
13:43.630 --> 13:44.830
and I hit run,

207
13:45.190 --> 13:50.190
you can see that this else block does not occur because it tried to do this,

208
13:50.980 --> 13:51.940
it failed

209
13:52.300 --> 13:57.300
and so it ended up jumping into the except block and it generated that file.

210
13:58.570 --> 14:02.530
But now that that file has been created, the next time I hit run,

211
14:02.800 --> 14:07.800
then this line of code is going to succeed and now it catches the next error in

212
14:08.560 --> 14:12.700
that try block. So if I change this to a key

213
14:12.700 --> 14:17.560
that it actually will recognize, then that next line also succeeds

214
14:17.920 --> 14:22.920
and finally it gets to this block and it actually prints out the thing that's

215
14:23.500 --> 14:27.250
inside a_file.txt which is just the word something.

216
14:28.120 --> 14:31.510
So we've now got try, except, else,

217
14:31.870 --> 14:35.950
and the last thing I want to show you is the keyword finally.

218
14:36.460 --> 14:41.460
So this finally is basically some code that's gonna run no matter what happens.

219
14:41.980 --> 14:42.813
And in our case,

220
14:42.820 --> 14:47.800
the most appropriate thing to do here is actually to close down the file because

221
14:47.800 --> 14:49.450
we're not using the with keyword

222
14:49.750 --> 14:54.750
so our file would actually stay open if we actually had an exception. And I'm

223
14:56.000 --> 14:57.650
going to go ahead and print

224
14:57.970 --> 14:59.890
<v 1>File was closed.</v>

225
15:00.790 --> 15:04.780
<v 0>Now our code basically will open up this file</v>

226
15:05.170 --> 15:08.890
and no matter if it succeeded or if it failed,

227
15:09.220 --> 15:14.220
it's going to close down that file so that we don't end up with an open file

228
15:14.530 --> 15:18.400
that we're not doing anything with. So finally is not often used,

229
15:18.730 --> 15:22.750
but sometimes it can be useful when you want some code to execute

230
15:22.990 --> 15:27.990
no matter if the code you are trying is succeeded or failed. In the next lesson,

231
15:29.440 --> 15:32.170
I'll show you how you can raise your own exceptions.