Here are our solutions for the day 19 exercises in the 30 Days of Python series. Make sure you try the exercises yourself before checking out the solutions!

1) Create a short program that prompts the user for a list of grades separated by commas. Split the string into individual grades and use a list comprehension to convert each string to an integer. You should use a try statement to inform the user when the values they entered cannot be converted.

Let's start by writing our input call to grab the list of grades. We can also use the split method to split the string we get back from input all on the same line.

grades = input("Please enter your grades, separated by commas: ").split(",")

Before we move on, let's consider what happens if the user enters something like this in response to our prompt:

76, 93, 84, 81

Here we have spaces after all of the commas, so our resulting grades list would be:

['76 ', '93 ', '84 ', '81']

This isn't a problem though, because Python is happy to accept the string '76 ' as a valid argument to int or float, and it will strip off the whitespace for us.

It's therefore not necessary to do something like this:

grades = input("Please enter your grades, separated by commas: ").split(",")
grades = [grade.strip() for grade in grades]

Now we get to the meat of the exercise. We need to try to convert each string to an integer, and then we need to catch any exceptions that arise from the user providing invalid values.

In the event that the user enters an invalid value, we're going to get a ValueError, so this is the exception we need to catch with our except clause.

grades = input("Please enter your grades, separated by commas: ").split(",")

try:
	pass
except ValueError:
	pass

Inside the try clause I'm going to create a list comprehension to convert each string to an integer. I'm then going to assign the result to grades. If you need a reminder on how list comprehensions work, take another look at day 15.

Inside the except clause I'm going to write a message informing the user that their data was in an invalid format.

In a more complete application, the rest of our code working with grades would likely go in an else clause, but we don't have to worry about that here.

grades = input("Please enter your grades, separated by commas: ").split(",")

try:
	grades = [int(grade) for grade in grades]
except ValueError:
	print("The grades you entered were in an invalid format.")

2) Investigate what happens when there is a return statement in both the try clause and finally clause of a try statement.

In order to complete this exercise, we're going to need to write a function, since we need a function actually return from.

We don't have to get too fancy here. This will do:

def func():
	pass

Now let's put our try statement in the function body. I recommend you use something different for the two return values so that we know where our values come from.

Something like the function below would be appropriate:

def func():
	try:
		return "Returned from the try clause!"
	finally:
		return "Returned from the finally clause!"

Now let's call our function and see what happens.

def func():
	try:
		return "Returned from the try clause!"
	finally:
		return "Returned from the finally clause!"


print(func())  # "Returned from the finally clause!"

Perhaps a little surprisingly, we get the value returned in the finally clause. This makes some sense though, because the finally clause always runs, and it will interrupt the return in the try clause. It effectively puts that return on hold while it does its own return.

The problem is that if we carry out the return in the finally clause, we end the function execution, so we never come back to do the one in the try clause. It just gets forgotten about.

3) Imagine you have a file named data.txt. Open it for reading using Python, but make sure to use a try block to catch an exception that arises if the file doesn't exist. Once you've verified your solution works with an actual file, delete the file and see if your try block is able to handle it.

The content of our data.txt file is something simple like this:

There is some data here!

It's not terribly important.

We also get told that the exception we need to watch our for is FileNotFoundError.

With that in mind, let's construct our try statement:

try:
	pass
except FileNotFoundError:
	pass

Inside our try clause we're going to write the code to access the file. I'm just going to print the file contents to the console. In the except clause I'm going to write a message to the user indicating that the file could not be found.

In a real application, we might take this opportunity to create the file for the user instead.

try:
	with open("data.txt", "r") as text_file:
		print(text_file.read())
except FileNotFoundError:
	print("Error: Couldn't find data.txt")

With that, we're done!