Exceptions: raising and handling

What are Exceptions

What are Exceptions

Exceptions - not a syntax, but a run-time errors (raised during the execution of a program)
There are many types of standard exceptions defined in Python :
ValueError, NameError, TypeError, IndexError, ZeroDivisionError,...
Standard Exceptions are hierarchically organized in Python:
Exception hierarchy

examples


			>>> user_number = int(input("Enter a number: "))
			Enter a number: ada
			# ValueError: invalid literal for int() with base 10: 'ada'

			print(i)
			#NameError: name 'i' is not defined

			>>> colors = ["red", "green","blue"]
			>>> print( colors[3] )
			# IndexError: list index out of range
		

Exceptions Handling

Exceptions Handling

When an exception is raised (thrown) you may want to take some actions, not just stopping the program.
You can take specific actions for each specific Exception Type

Syntax


			try:
				# code, which can raise an exception
			except ExceptionType as e:
				# do something if an ExceptionType was raised
			else:
				# do something if there was no Exception
			finally:
				# do something no matter if an Exception was raised or not.
				# (useful for closing DB connections, etc.)
		
except is executed only when an exception from ExceptionType was raised in try code. ExceptionType is any of the built-in Exception Classes or a User-defined Exception Class.You may have more than one except clauses for different Exception Types
else is executed only when the code in try clause did not raise any exception.
finally is always executed!

Syntax Examples


			try:
				# code, which can raise an exception
				user_number = int(input("Enter a number: "))
			except Exception as e:
				# do something if an Exception was raised
				print("You did not enter a number!")
			else:
				# do something if there was no Exception
				print("Your number is ", user_number)
			finally:
				# do something no matter if an Exception was raised or not
				print("That was all!")
		

Handling different Exception Types

Handling different Exception Types

Handling specific Exception Type


			try:
				# code, which can raise an exception
			except ExceptionType:
				# do something only if an ExceptionType was raised
		

			try:
				user_number = int(input("Enter a number: "))
			except ValueError:
				print("You did not enter a number!")
		

Handling multiple Exception Type


			try:
				# code, which can raise an exception
			except ExceptionType1:
				# do something only if an ExceptionType1 was raised
			except ExceptionType2:
				# do something only if an ExceptionType2 was raised
		

			try:
				user_number = int(input("Enter a number: "))
				res = 10/user_number
			except ValueError:
				print("You did not enter a number!")
			except ZeroDivisionError:
				print("Enter a number different from zero (0)!")
		

Handling any exception


			try:
				# code, which can raise an exception
			except:
				# do something if any exception was raised
		
if you use the expression-less except clause, it should be the last except clause

Handling any exception - simple example


			x = 5
			y = 0
			try:
				res = x/y
			except:
				print("Oops! Something went wrong!")

			# Oops! Something went wrong!
		

Handling any exception - example 1


			def get_user_number():
				user_number = int(input("Enter a number: "))
				# we forgot to return user_number, thus None is returned

			try:
				x = get_user_number()
				res = 10/x
				print("Result is {}".format(res))
			except ValueError:
				print("You did not enter a number!")
			except ZeroDivisionError:
				print("Enter a number different from zero (0)!")
			except:
				print("Oops! Something went wrong!")
		

Handling any exception - example 2

Everything looks perfect? Try to enter a CTRL+D : )


			def get_user_number():
				user_number = int(input("Enter a number: "))
				return user_number

			try:
				x = get_user_number()
				res = 10/x
				print("Result is {}".format(res))
			except ValueError:
				print("You did not enter a number!")
			except ZeroDivisionError:
				print("Enter a number different from zero (0)!")
			except:
				print("Oops! Something went wrong!")
		

Raising Exceptions

Raising Exceptions

Why?

Often, we want when exception occurs the program to stop, but we need to do something before that.
the rasie statement allows us, to handle the exception, and to raise it after.

			try:
				user_number = int(input("Enter a number: "))
			except ValueError:
				print("~"*30)
				print("You did not enter a number!")
				print("~"*30)
				raise
		

The raise statement

The raise statement allows the programmer to force a specified exception to occur.
You can pass to raise an ExceptionType to be raised
Or you can skip the ExceptionType and write just raise
In that case, the last error will be re-raised
The raise statement @python3 docs

raise ExceptionType - example


			user_name = input("Enter your name: ")
			if user_name == "pesho":
				raise KeyboardInterrupt
		

surely, you do not want to do that - it's just an example!

raise without arguments - example

A common case for raise without argument is when you want the error to be thrown as normally, but to take some actions (logging, rollback, etc.) before that

			try:
			  db_insert()
			except:
			  rollback()
			  raise
			else:
			  commit()
		

raising custom exceptions

A common use-case for raise statement is when we want to raise a custom exception (especially useful when writing APIs)

			# define custom exception
			class UserNameError(Exception):
			  pass

			# do the potential dangerous stuff in try:
			try:
			  user_name = input("Enter your name: ")
			  if len(user_name)<3:
			    raise UserNameError
			except UserNameError:
			  print("User name must be at least 3 symbols long")
			except:
			    print('Oops! Something went wrong!')
		

Resources

Resources

Blogs, wiki, docs

Handling Exceptions @wiki.python.org
Errors and Exceptions @ The Python Tutorial

Exercises

get_string_from_user.py

Task

define the function get_string_from_user() which will get any user input and returns it as string.
The function must handle any possible errors, like entering CTRL+D or CTRL+C, by printing:
"***Oops, something went wrong! Try again!"
If any error occurred - ask the user again, without terminating the program

Function signature and docstring:


			def get_string_from_user(msg):
				"""
					Summary:
						Asks the user to enter a string and
						- if any error occurs => print:
							"***Oops, something went wrong! Try again!" and ask again

						Returns the user input, as string, when no errors occurred.

					Usage:
						user_input = get_string_from_user("enter a user name: ")

					Arguments:
						msg {[string]} -- [the string to be displayed to the user,]

					Returns:
						[string] -- [the string entered from user]
				"""
		

Program Test


			def get_string_from_user(msg):
				# your definition here

			user_name = get_string_from_user("Enter your name, please: ")
			user_place = get_string_from_user("Where are you from?: ")
			print("Hello {}! How is the weather in {} today?".format(user_name, user_place))
		

Program Test - RunTime


			$ python3.6 get_string_from_user.py

			Enter your name, please: ^C
			***Oops, something went wrong! Try again!

			Enter your name, please: iva
			Where are you from?: Sofia, Bulgaria

			Hello iva! How is the weather in Sofia, Bulgaria today?
		

get_float_from_user.py

Task

define the function get_float_from_user() which will get from the user a valid python number data-type and will returns it as float.
The function must handle ValueError, by outputing a message "***Enter a number, please!" and asking the user to enter again.
The function must handle any other possible errors, like entering CTRL+D or CTRL+C, by printing "\n***Oops, something went wrong! Try again!\n" and asking the user again.

Function signature and docstring:


			def get_float_from_user(msg):
				"""
					Summary:
						Asks the user to enter a number and
						- if he/she entered no valid python's number value => print:
							"***Enter an number, please!" and ask again.
						- if any other error occurs => print:
							"***Oops, something went wrong! Try again!" and ask again

						Returns the user input, as float, when no errors occurred.

					Usage:
						user_number = get_float_from_user("the message to show to the user")

					Arguments:
						msg {[string]} - - [the message to show to the user]

					Returns:
						[float] - - [the number entered from user, converted to float]
				"""
		

Program Test


			def get_float_from_user(msg):
				# your definition here

			user_height = get_float_from_user("I need to know your height in centimetres: ")
			user_weight = get_float_from_user("And your weight in kilograms: ")
			print("Your height is: {:5.2f}cm. and you weight {:.2f}kg.".format(user_height, user_weight))
		

Program Test - RunTime


			$ python3.6 get_float_from_user.py

			I need to know your height in centimetres: pesho
			***Enter a number, please!

			I need to know your height in centimetres: ^C
			***Oops, something went wrong! Try again!

			I need to know your height in centimetres: 195
			And your weight in kilograms: 98.64

			Your height is: 195.00cm. and you weight 98.64kg.
		

BMI Improved

Task

Use your niew functions: get_string_from_user() and get_float_from_user() to improve the user experience in the BMI calculation program, as given in Function - Exercises theme.

Submission

Please, prefix your filenames/archive with your name initials, before sending.
For instance: iep_task_name.py or iep_tasks.rar
Send files to progressbg.python.course@gmail.com

These slides are based on

customised version of

Hakimel's reveal.js

framework