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(",")
``````

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:
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: