-: Hi, guys, and welcome back.
In this video, we're going to learn about errors in Python.
What we've got here is a simple divide function,
that takes in two parameters.
If the divisor is equal to zero,
it prints that it cannot be zero and then returns.
Otherwise, it'll return the dividend divided by the divisor.
If we run this code, you should see that you get a print,
Divisor cannot be zero.
However, if you use this function inside a programme,
potentially, you may encounter a problem,
which is that your programme expects the function to work
and there's nothing in the function that says otherwise,
other than a print statement,
which really is meant for your users to see.
For example, let's say that we've got a set of grades
and we want to calculate the average,
and we have a programme like this one.
Welcome to the average grade programme,
and the average is equal to divide
of some grades by len(grades).
Obviously, not the most useful programme,
but just bare with me while I explain why errors
are useful in Python.
What we're gonna get here, if we run this programme
and we print the average grade is average,
is, of course, the average grade.
It says the average grade is 90.5, that's it.
Now, very good.
However, if we want to print a nicer error message,
we start having to do some pretty crazy stuff,
if we are not using errors.
For example, let's say that we don't have any grades yet.
For example, imagine our programme adds the grades over time
or something like that, and there are no grades.
What you'll get is, welcome to the average grade programme,
divisor cannot be zero, the average grade is none.
Now, not the greatest functionality here in our programme,
and this is caused by this function printing something out
that is essentially just mathematical,
it's unrelated to the context of the programme.
This programme here talks about student grades,
and that's what the user is expecting to read about.
This programme here, or this bit of code here,
talks about mathematics,
whether you can divide a number by zero or not.
Though they are related, but you don't wanna be
printing divisor cannot be zero, when the user is expecting
an average of a bunch of grades.
However, it is the only way that we can do something
unless we check for the divisor being zero out here.
So if we say, if len(grades) equal zero,
then you can say you don't have any grades.
You don't have grades yet.
Or we could do this instead, and then,
if you want, you can also put that same check here,
you don't need this return.
But as you can see, this is getting a little bit messy now,
because you are removing logic from a division function
that really should be in there,
or it could be in there,
and putting it in your main programme.
It's making your main programme longer,
it's making your function shorter,
but it's doing a bit less.
This function here would check for division by zero,
and then do something a bit more useful,
rather than print think out.
So, here come the errors.
In Python, errors are often used for flow control,
very much like if statements.
Though, by allowing your functions to raise errors,
you're going to then be able to catch them
in your code and handle them.
Here's what we're gonna do, if divisor == 0,
now we are going to raise something
called a ZeroDivisionError,
which is a error that comes with Python,
and you're gonna say divisor cannot be zero.
Now, this message here inside the brackets means
that this error is going to have a message attached to it.
And what we're doing here is we're saying raise,
the keyword raise and a space,
and then the exception name or the error name,
exception and errors are the same thing,
and then the bracket.
So we're creating an exception object in here.
This is another class that is defined inside Python.
So if we try now to divide the sum of grades
by the len of grades, knowing that there are no grades,
what you're gonna get is,
welcome to the average grade programme.
And then you're going to get a very nice traceback.
So let me just make that a bit bigger for you.
A traceback shows you where the problem happened.
And here it says that the last set of lines here
tells you where the error originated,
and it says it originated in code.py,
which is our file, line three,
which is this one here, in the divide function.
And the problem was that you raised the error yourself.
So because you raised an error the error happened.
If you didn't raise the error
the error wouldn't have happened,
so that it what it's telling you there.
And then it's saying that the next thing up,
what called this divide function,
was this line here, line 11.
And it's showing you the line there
that caused this function to be called,
which then caused the exception.
So you can see how it bubbles up,
and in our case it's only got two lines here,
but sometimes these can be really long,
and they can tell you, this called that
and that called that, and that called that,
and so on, and eventually an error happened.
And what you've got at the very end
is the error itself, a ZeroDivisionError,
divisor cannot be zero.
Clearly we don't wanna be showing our users this,
but this is excellent and really helpful
for when you're coding.
So errors help you track down problems
and where and why they happened.
So errors give developers a great tool for debugging,
or finding where the problem is.
So that's one great plus of using errors.
The other thing is that now you can catch the error.
You can say, okay, if an error happens in this line
I wanna do something.
And the syntax for that in Python is a try-except block.
So we're going to try to do that,
and then if a ZeroDivisionError happens,
then we can print, there are no grades yet in your list.
So, try, and then in an indented block,
we put the code that we wanna try,
this can be one line or it can be many lines.
And then in the same indentation level as the try,
we put except and the type of exception
that we wanna look out for.
If this exception happens in this code,
then we will run this stuff here.
So now our code can handle this ZeroDivisionError,
meaning that if we get a ZeroDivisionError,
we're not going to print the traceback,
we are not going to print divisor cannot be zero.
We are going to print, there are no grades yet in your list.
However, if you use the divide function
somewhere else in your programme
and you don't wrap it in a try-except block,
the error will still happen and the divisor cannot be zero
will still be printed out, and the traceback.
So this allows you to handle these errors
in different ways throughout your programme,
which means that this divide function
is concerned about the mathematics of division,
this piece of code here is concerned
about how to handle the mathematics
in the context of your programme,
which is there are no grades yet in your list.
Notice that here in the except block
you can do as e, and what this does in Python
is it creates a variable called e,
and puts inside it the value of the error, if there is one.
So if the ZeroDivisionError is created with this message,
then e will contain that.
And e can be anything you want,
so you can call it exception,
or you can call it e, or you can call it Bob if you want.
And we can print e as well, if you like,
just to see what happens, and what you get is this stuff.
So you get there are no grades yet in your list,
and you get divisor cannot be zero.
Afterwards, because there was an error in this line,
the average variable was never created,
because this caused the error,
which means our code jumped directly here.
So, when you run line 17, the variable does not exist.
Therefore, you may wanna put your variable in the same block
as your variable definition.
Now running that will give you,
welcome to the average grade programme,
divisor cannot be zero, there are no grades in your list.
If you remove this print e, then that will get rid of
the divisor cannot be zero, and you'll get,
Welcome to the average grade programme,
there are no grades yet in your list.
This is exactly what we wanted,
and using errors allows our programme to handle
both the maths of the operation
and also the programme context.
As well as ZeroDivisionErrors,
there's a whole bunch more built-in errors,
errors that come with Python,
that you can create for different things.
All errors are handled the same way,
but when you see in your programme
that a ZeroDivisionError has happened,
it tells you that you probably tried
to divide something by zero.
Know there are other types of errors,
so that you as the programmer can more easily tell
what happened and what went wrong.
Some examples are a TypeError,
or when something was the wrong type,
and you would raise a TypeError, that.
You've got ValueError, or when something
had the wrong value, or an unexpected value.
You've got RuntimeError, or most other things.
And you can also create your own errors,
but we're going to be doing that in the next video.
Finally, instead of putting this line of code here
together with the try, you can actually put it afterwards,
but tell Python to only run it if this succeeded.
So the way you do that in Python
is you put an else, actually, in there.
And you put this line of code in here.
So this is a different way of running that same code,
and what happens here is you try to run this,
if an error happened then you run this,
and if no error happened that means that this line of code
ran successfully, then you run this.
So the reason why we may wanna use the else,
instead of putting this line of code here,
is if we want to catch some specific errors
in a specific line of code, and we don't wanna put
all of our code in the same block.
Finally, if you wanna run a piece of code always,
no matter whether there is an error, or no error,
you can use the finally clause here
to print something else out,
or you need to do anything else.
So these are the different clauses,
try, except, else and finally, and they run in that order.
You can have multiple except clauses if you want.
For example, if this function here could raise
a ZeroDivisionError, or potentially somewhere else,
it could raise a ValueError,
you can catch them separately,
and handle them differently if you want.
I'm just showing you the syntax there,
but we're gonna look as some examples in just a moment.
Imagine you have a list of students
and each one has a bunch of grades,
here is when using this function might come in handy.
'Cause you've got Bob, Rolf, and Jen,
and Rolf doesn't have any grades.
Though we can try to iterate over the student's list,
get the name and grades, and calculate the average
for a given student, printing their average afterwards.
Of course, Rolf's average will fail,
though we can except in a ZeroDivisionRrror,
and say, error, Rolf has no grades.
Otherwise, if all of them have grades,
we can print that all the student averages
were calculated and finally at the end, no matter what,
we can print the end of the student average calculation.
So if we run this we will encounter an error,
we will print Bob's average and then Rolf will error as out.
Note, Bob averaged 82.5 and we get an error,
Rolf has no grades.
But if we put a grade for Rolf and we press play again,
now you see that all of them run to completion
and we get back a message saying
that all student averages were calculated,
because that's in our else.
So to recap, a try allows you to run a piece of code,
then you can catch or except some exception,
or multiple exceptions if you want,
handling them in that block of code.
The else keyword, together with try and except,
allows you to run some code if there are no errors.
And finally, you can run a piece of code at the very end,
no matter what, whether there's an error, or not,
in case you wanna print a message,
or do some clean up at the end.
That's it for this video, thank you for joining me,
and I'll see you in the next one.