OPS445 Lab 5: Difference between revisions
No edit summary |
|||
(10 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
So far, you have created Python programs to prompt a user to input data from the keyboard. When creating Python programs, you may also need to process large volumes of information, or store processed data. Since many tasks that system administrators perform deal with files: reading and writing files is a crucial skill. | So far, you have created Python programs to prompt a user to input data from the keyboard. When creating Python programs, you may also need to process large volumes of information, or store processed data. Since many tasks that system administrators perform deal with files: reading and writing files is a crucial skill. | ||
Line 157: | Line 155: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Now create a new file called file2.txt, but this time call multiple write() methods in sequence. You will often write to a file multiple times inside a loop: | * Now create a new file called file2.txt, but this time call multiple write() methods in sequence. You will often write to a file multiple times inside a loop:<syntaxhighlight lang="python"> | ||
f = open('file2.txt', 'w') | f = open('file2.txt', 'w') | ||
f.write('Line 1\nLine 2 is a little longer\nLine 3 is as well\n') | f.write('Line 1\nLine 2 is a little longer\nLine 3 is as well\n') | ||
Line 327: | Line 325: | ||
cd ~/ops435/lab5/ | cd ~/ops435/lab5/ | ||
pwd #confirm that you are in the right directory | pwd #confirm that you are in the right directory | ||
ls CheckLab5.py || | ls CheckLab5.py || wget http://ops345.ca/ops445/CheckLab5.py | ||
python3 ./CheckLab5.py -f -v lab5b | python3 ./CheckLab5.py -f -v lab5b | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Before proceeding, make certain that you identify all errors in lab5b.py. When the checking script tells you everything is OK - proceed to the next step. | * Before proceeding, make certain that you identify all errors in lab5b.py. When the checking script tells you everything is OK - proceed to the next step. | ||
= | = Exceptions and Error Handling = | ||
Every programmer and every program runs into errors all the time. You should expect that it will happen for any code that you write. In Python, when an error occurs, the python runtime raises an '''exception'''. This section will teach you to catch these exceptions when they happen and to allow the program to continue running, or to stop program execution with a readable error message. | |||
There | There exists a <u>massive number</u> of exceptions. If you write a lot of a certain type of code: you'll become familiar with the exceptions the methods you typically use throw. Online references can be useful for new-to-you methods. You also have an option to not handle exceptions at all (as you did so far in this course), but your resulting program may not be acceptable, depending on where and how it's used. | ||
In this section, we will provide examples of how to handle a few exceptions | In this section, we will provide examples of how to handle a few exceptions in Python. | ||
* To start, create a new temporary python program. Before attempting to handle exception errors, let's create an error, and then see how to can "handle" it:<syntaxhighlight lang="python"> | |||
print( | print("5" + 10) | ||
</ | </syntaxhighlight>You should get an exception error similar to the following:<syntaxhighlight lang="bash:> | ||
--------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ||
Traceback (most recent call last) | Traceback (most recent call last) | ||
Fiel "<stdin>", line 1, in <module> | Fiel "<stdin>", line 1, in <module> | ||
TypeError: Can't convert 'int' object to str implicitly | TypeError: Can't convert 'int' object to str implicitly | ||
</syntaxhighlight> | |||
* Click on the link [https://docs.python.org/3/library/exceptions.html#concrete-exceptions] and scroll down to '''TypeError'''. You've seen this error before so you already know what the problem is, but take a couple of minutes to read the documentation. It will be hard to understand what they're talking about, but this sort of exercise is worth the time and effort. | |||
If we don't want the user of our program to have to learn how to read Python exceptions (which is a very good idea), we can catch/trap/handle this exception when it happens. This is done with a specific block of code called a [https://docs.python.org/3/tutorial/errors.html#handling-exceptions '''try clause'''] where you place code in-between the '''try:''' and the '''except:''' coding blocks. In a general sense, it works like a modified if-else statement, where the try statement acts as a test, and the except statement will or will not handle the exception depending if it occurs or does NOT occur. That is to say, If no error occurs in the code contained in the '''try''' section, the script will continue as usual but if an error occurs in the "try" section, then it can be handled in whatever way you feel is appropriate (like an user-friendly error message). | |||
Let's demonstrate handling our TypeError error with code that first does not contain an error and then similar code that DOES generate an error. | |||
* The following code does NOT generate an error:<syntaxhighlight lang="python"> | |||
try: | try: | ||
print(5 + 10) | print(5 + 10) | ||
print("Still inside try block") | |||
except TypeError: | except TypeError: | ||
print( | print("At least one of the values is NOT an integer") | ||
print("End of program") | |||
</ | </syntaxhighlight> | ||
* The following code handles an exception error to provide user-friendly feedback that at least one of the values is not an integer:<syntaxhighlight lang="python"> | |||
try: | try: | ||
print(5 + | print(5 + "ten") | ||
print("Still inside try block") | |||
except TypeError: | except TypeError: | ||
print( | print("At least one of the values is NOT an integer") | ||
print("End of program") | |||
</ | </syntaxhighlight> | ||
: | |||
Walk through what happens in each of the two examples below. Notice that once an exception is thrown inside a '''try''' block: execution of the code stops, and jumps to the '''except''' block. | |||
If an exception happens and it's not handled with try/except: your entire program will crash. That is by design, and is a good thing. You need to handle exceptional circumstances in your program, the computer can't do that for you. | |||
Exceptions work the same way in all the programming languages that I've seen that have them, so the mechanics of handling exceptions is worth learning, even though it is a lot more code to write. | |||
* Generate another type of error by attempting to open a file that doesn't exist:<syntaxhighlight lang="python"> | |||
f = open('filethatdoesnotexist', 'r') | f = open('filethatdoesnotexist', 'r') | ||
</ | |||
print("End of program") | |||
</syntaxhighlight> | |||
* Now, catch and handle this exception:<syntaxhighlight lang="python"> | |||
try: | try: | ||
f = open( | f = open("filethatdoesnotexist", "r") | ||
print("This is right after the open() call.") | |||
f.close() | f.close() | ||
except FileNotFoundError: | except FileNotFoundError: | ||
print(' | print("Tried to open filethatdoesnotexist for reading but it doesn't exist.") | ||
</ | |||
print("End of program") | |||
</syntaxhighlight> | |||
You can catch multiple exceptions at the same time, such as does not exist, is a directory, or we don't have permission. | |||
{{Admon/important|1= Lazy error handling|2= The reason you often get a useless annoying error message from technology is that a programmer was too lazy to handle different types of errors separately, keep that in mind when you decide how much work to put into your exception handling.}} | |||
* Try running the code below with different paths: a file that does not exist, a file which does exist but you don't have permissions to read, or a directory instead of a regular file:<syntaxhighlight lang="python"> | |||
try: | try: | ||
f = open( | f = open("filethatdoesnotexist", "r") | ||
f.close() | f.close() | ||
except (FileNotFoundError, PermissionError, IsADirectoryError): | except (FileNotFoundError, PermissionError, IsADirectoryError, IOError): | ||
print( | print("Failed to open file") | ||
</ | |||
print("End of program") | |||
</syntaxhighlight> | |||
* By taking the time to view the [https://docs.python.org/3/library/exceptions.html#exception-hierarchy Python Exception Hierarchy], you can see how errors get caught in python. The options '''FileNotFoundError''', '''PermissionError''', and '''IsADirectory''' are all inherited from '''OSError'''. This means that while using more specific errors might be useful for better error messages and handling, if you can figure out what specific errors may happen to your code. | |||
* Another way to catch multiple exceptions is with separate <code>except</code> bloks:<syntaxhighlight lang="python"> | |||
try: | try: | ||
f = open(abc, | f = open("abc", "r") | ||
f.close() | f.close() | ||
except (FileNotFoundError, PermissionError): | except (FileNotFoundError, PermissionError): | ||
print( | print("File does not exist or wrong permissions") | ||
except IsADirectoryError: | except IsADirectoryError: | ||
print( | print("File is a directory") | ||
except OSError: | except (OSError, IOError): | ||
print( | print("Unable to open file") | ||
except: | except: | ||
print( | print("unknown error occured") | ||
</syntaxhighlight> | |||
=== | When catching multiple exceptions, make certain to catch the <u>lowest</u> ones contained in the exception-hierarchy first. For example, if you put 'Exception' first, both 'OSError' and 'FileNotFoundError', would never get caught.<br><br>'''TIP:''' In python it's usually best to 'try:' and 'except:' code rather than to attempt to anticipate everything that could go wrong with '''if''' statements. For example, instead of checking to see if a file exists and we have read permissions, it can be better to just try and read the file and fail and catch any errors with 'OSError'. | ||
=== Practice Handling Exceptions === | |||
* Create the '''~/ops435/lab5/lab5c.py''' program. Use the following as a template:<syntaxhighlight lang="python"> | |||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||
def add(number1, number2): | def add(number1, number2): | ||
# Add two numbers together, return the result, | # Add two numbers together, return the result, in case of an exception: | ||
# return the string 'error: could not add numbers' | |||
def read_file(filename): | def read_file(filename): | ||
# Read a file, return a list of all lines, | # Read a file, return a list of all lines, in case of an exception: | ||
# return the string 'error: could not read file' | |||
if __name__ == '__main__': | if __name__ == '__main__': | ||
Line 421: | Line 445: | ||
print(read_file('seneca2.txt')) # works | print(read_file('seneca2.txt')) # works | ||
print(read_file('file10000.txt')) # exception | print(read_file('file10000.txt')) # exception | ||
</syntaxhighlight> | |||
'''Sample Run 1:'''<syntaxhighlight lang="bash"> | |||
python3 lab5c.py | python3 lab5c.py | ||
15 | 15 | ||
Line 432: | Line 455: | ||
['Line 1\n', 'Line 2\n', 'Line 3\n'] | ['Line 1\n', 'Line 2\n', 'Line 3\n'] | ||
error: could not read file | error: could not read file | ||
</ | </syntaxhighlight> | ||
'''Sample Run 2 (with import):'''<syntaxhighlight lang="python"> | |||
import lab5c | import lab5c | ||
lab5c.add(10,5) | lab5c.add(10,5) | ||
15 | # 15 | ||
lab5c.add('10',5) | lab5c.add('10',5) | ||
15 | # 15 | ||
lab5c.add('10','5') | lab5c.add('10','5') | ||
15 | # 15 | ||
lab5c.add('abc','5') | lab5c.add('abc','5') | ||
'error: could not add numbers' | # 'error: could not add numbers' | ||
lab5c.add('hello','world') | lab5c.add('hello','world') | ||
'error: could not add numbers' | # 'error: could not add numbers' | ||
lab5c.read_file('seneca2.txt') | lab5c.read_file('seneca2.txt') | ||
['Line 1\n', 'Line 2\n', 'Line 3\n'] | # ['Line 1\n', 'Line 2\n', 'Line 3\n'] | ||
lab5c.read_file('file10000.txt') | lab5c.read_file('file10000.txt') | ||
error: could not read file' | # error: could not read file' | ||
</syntaxhighlight> | |||
* Download the checking script and check your work:<syntaxhighlight lang="bash"> | |||
cd ~/ops435/lab5/ | cd ~/ops435/lab5/ | ||
pwd #confirm that you are in the right directory | pwd #confirm that you are in the right directory | ||
ls CheckLab5.py || wget | ls CheckLab5.py || wget http://ops345.ca/ops445/CheckLab5.py | ||
python3 ./CheckLab5.py -f -v lab5c | python3 ./CheckLab5.py -f -v lab5c | ||
</ | </syntaxhighlight> | ||
* Before proceeding, make certain that you identify any and all errors in lab5c.py. When the checking script tells you everything is OK before proceeding to the next step. | |||
= Submit evidence of your work = | |||
Run the following command in a terminal:<syntaxhighlight lang="bash"> | |||
cd ~/ops435/lab5 | |||
python3 ./CheckLab5.py -f | |||
</syntaxhighlight> | |||
* The output of the lab check command must say '''OK'''. | |||
* To show that you completed the lab, submit a screenshot of the terminal with that output. | |||
[[Category: | [[Category:OPS445]] |
Latest revision as of 14:59, 22 February 2025
So far, you have created Python programs to prompt a user to input data from the keyboard. When creating Python programs, you may also need to process large volumes of information, or store processed data. Since many tasks that system administrators perform deal with files: reading and writing files is a crucial skill.
It is very important to provide logic in your Python program in case it encounters an error. An example would be an invalid path or trying to close a file that is already closed. The second part in this lab will look into how Python interpreters handle errors (commonly referred to as exception handling) at run time, and learn how to write Python code that will run gracefully even when problems occur during program execution.
Working with Files
You will now learn how to open text files, read the contents within a text file, process the contents, and finally write the processed contents back into a file. These operations are very common, and are used extensively in programming. Examples of file operations would include situations such as logging output, logging errors, reading and creating configuration/temporary files, etc.
Files are accessed through the use of file objects. An object is a variable which stores data in the form of attributes (data contents) and methods (functions).
Reading Data From Files
- Create a new python file for testing.
- Create a new text file in the lab5 directory:
cd ~/ops435/lab5 vi ~/ops435/lab5/data.txt
- Place the following content inside the new text file and save it:
This is the second line Third line Last line
In order to read data from a text file, we need to create an object that will be used to access the data in a file. In some programming languages (like C) this is called a file descriptor, or a file pointer. In Python, it's an object.
- Define a variable called f in order to help retrieve content from our text file.:
f = open("data.txt", "r")
The open() function takes two string arguments: a path to a file, and a mode option (to ask for reading, writing, appending, etc). The open() function will return a file object to us, this file object will allow us to read the lines inside the file. Here are the most useful functions for text file manipulation:
f.read() # read all lines and stores in a string
f.readlines() # read all lines and stores in a list
f.readline() # read first line, if run a second time it will read the second line, then third
f.close() # close the opened file
- Next, read data from the opened file and store the contents in a variable called
read_data
, and then confirm the contents of the variableread_data
:data_from_file = f.read() print(data_from_file)
After you're done working with file, you should close the file. There are good reasons not to forget this. It is sometimes useful to first confirm that the file is still open prior to closing it. But really you should know - it's your code that would have opened it:
f.close() # This method will close the file
Let's take some time to revisit the file read sequence. The following code sequence will open a file, store the contents of that file into a variable, and close the file:
f = open('data.txt', 'r') # Open file
data_from_file = f.read() # Read from file
f.close() # Close file
data_from_file in this case contains the data from the file in a single long string. The end of each line in the file is part of that string, as the special character '\n' which represents the newline character.
- Often it is convenient to split the string on newline characters, so each line is stored as an item in a list:
data_from_file.split('\n') # Returns a list list_of_lines = data_from_file.split('\n') # Saves returned list in variable print(list_of_lines)
- There are other methods the we can use with our object f to place lines from our file into a list. Try these two:
# METHOD 1: f = open('data.txt', 'r') # The method1 list is constructed by reading lines from the file descriptor: method1 = list(f) f.close() print(method1) # METHOD 2: f = open('data.txt', 'r') # The readlines() method returns a list with each element being one line from the file: method2 = f.readlines() f.close() print(method2)
Practice Reading Files
- Create the ~/ops435/lab5/lab5a.py program. Use the following as a template:
#!/usr/bin/env python3 def read_file_string(file_name): # Takes a filename string, returns a string of all lines in the file def read_file_list(file_name): # Takes a filename string, returns a list of lines without new-line characters if __name__ == '__main__': file_name = 'data.txt' print(read_file_string(file_name)) print(read_file_list(file_name))
- This program will read the same file (data.txt) that you previously created
- The read_file_string() function should return a string
- The read_file_list() function should return a list
- The read_file_list() function must remove the new-line characters from each line in the list
- Both functions must accept one argument which is a string
Sample Run 1:
python3 lab5a.py
Hello World
This is the second line
Third line
Last line
['Hello World', 'This is the second line', 'Third line', 'Last line']
Sample Run 2 (with import):
import lab5a
file_name = 'data.txt'
print(lab5a.read_file_string(file_name))
# Will print 'Hello World\nThis is the second line\nThird line\nLast line\n'
print(lab5a.read_file_list(file_name))
# Will print ['Hello World', 'This is the second line', 'Third line', 'Last line']
- Download the checking script and check your work:
cd ~/ops435/lab5/ pwd #confirm that you are in the right directory ls CheckLab5.py || wget http://ops345.ca/ops445/CheckLab5.py python3 ./CheckLab5.py -f -v lab5a
- Before proceeding, make certain that you identify all errors in lab5a.py. When the checking script tells you everything is OK - proceed to the next step.
Writing To Files
Up to this point, you have learned how to access text from a file. In this section, you will learn how to write text to a file. Writing data to a file is useful for creating new content in a file or modifying existing data contained within a file. If you don't have programming experience: the modifying part is much more complicated than you might imagine.
When opening a file for writing, the 'w' parameter is passed to the open() function. When the 'w' option is chosen: previous (existing) content inside the file is deleted. This deletion takes place the moment the open() function is executed, not when writing to the file. If the file that is being written to doesn't exist, the file will be created when open() is called.
- Create a temporary Python file and open a non-existent data file (called file1.txt) for writing:
f = open('file1.txt', 'w')
- To confirm that the new file now exists and is empty, run this in the shell:
ls -l file1.txt
To add text to the file, you can use the write() method for the file object. Usually you end every line in a text file with the special character '\n' to represent a "new line". Multiple lines may be written using a single write operation: simply put the special character '\n' wherever each line should end.
- Add three line to your data file:
f.write('Line 1\nLine 2 is a little longer\nLine 3 is too\n')
- Once the write() method has completed, the final step is to close() the file. The file MUST be closed properly or else data will not consistently be written to the file (the same way you have to eject a USB storage device in your operating system before you yank it out):
f.close()
- View the contents of the file in the shell to make sure the data was written successfully:
cat file1.txt
- Now create a new file called file2.txt, but this time call multiple write() methods in sequence. You will often write to a file multiple times inside a loop:
f = open('file2.txt', 'w') f.write('Line 1\nLine 2 is a little longer\nLine 3 is as well\n') f.write('This is the 4th line\n') f.write('Last line in file\n') f.close()
- Run the following shell command to confirm that the contents were written to file2.txt:
cat file2.txt
- Backup both of your newly-created files and confirm that they were backuped up:
cp file1.txt file1.txt.bk cp file2.txt file2.txt.bk ls -l file*
- Let's see what can happen if you perform an incorrect write() operation. Add this to the end of your temporary python program:
f = open('file2.txt', 'w')
- And then check file2.txt:
cat file2.txt
You should notice that the previous content in your file2.txt file was lost. Why do you you think the previous data is no longer there?
- Restore your file from the backup and verify the backup restoration:
cp file2.txt.bk file2.txt cat file2.txt
To avoid overwriting the contents of a file, we can open the file for appending instead of writing (the difference in those two words is technical language, not human english).
- Use the option a instead of w to to append to a file:
f = open('file1.txt', 'a') f.write('This is the 4th line\n') f.write('Last line in file\n') f.close()
- Check your file1.txt contents, you'll see that the two lines written above are appended to the previous content in the file.
The final thing to consider when writing to files is that write() will only accept a string as an argument. This means that before trying to write integers, floats, lists, or dictionaries to a file, first either convert the value using str() function or extract the specific strings from items in the list.
- In this example we convert a single number and all the numbers in a list to strings before writing them to a file:
my_number = 1000 my_list = [1,2,3,4,5] f = open('file3.txt', 'w') f.write(str(my_number) + '\n') for num in my_list: f.write(str(num) + '\n') f.close()
- Check your file3.txt contents to confirm that all the numbers have been written to it.
Practice Writing to Files
- Copy ~/ops435/lab5/lab5a.py to ~/ops435/lab5/lab5b.py
- Add the following functions below the two functions that you have already defined:
def append_file_string(file_name, string_of_lines): # Appends the string_of_lines to the end of the file named file_name. def write_file_list(file_name, list_of_lines): # Writes all items from list_of_lines to the file named file_name # where each item is one line. def copy_file_add_line_numbers(file_name_read, file_name_write): # Reads data from the file named file_name_read, writes that data # to the file named file_name_write. # Adds a line number to each line in the new file.
- Replace the main section of your program with the following:
if __name__ == '__main__': file1 = 'seneca1.txt' file2 = 'seneca2.txt' file3 = 'seneca3.txt' string1 = 'First Line\nSecond Line\nThird Line\n' list1 = ['Line 1', 'Line 2', 'Line 3'] append_file_string(file1, string1) print(read_file_string(file1)) write_file_list(file2, list1) print(read_file_string(file2)) copy_file_add_line_numbers(file2, file3) print(read_file_string(file3))
- Implement the functions following these specifications:
- append_file_string():
- Takes two string arguments.
- Appends to the file (Argument 1) all data from the string (Argument 2).
- write_file_list():
- Takes two arguments: a string and a list.
- Writes to the file (Argument 1) all the lines from the list (Argument 2).
- copy_file_add_line_numbers():
- Takes two arguments: Both are filenames (which are strings).
- Reads all the lines from the first file (Argument 1), and writes all those lines into second file (Argument 2), while adding line numbers.
- Line numbers should be added to the beginning of each line with a colon next to them (see sample output below for reference).
- Hint: Use an extra variable for the line number.
- append_file_string():
Sample Run 1:
rm seneca1.txt seneca2.txt seneca3.txt
./lab5b.py
First Line
Second Line
Third Line
Line 1
Line 2
Line 3
1:Line 1
2:Line 2
3:Line 3
Sample Run 2 (run second time):
python3 lab5b.py
First Line
Second Line
Third Line
First Line
Second Line
Third Line
Line 1
Line 2
Line 3
1:Line 1
2:Line 2
3:Line 3
Sample Run 3 (with import):
import lab5b
file1 = 'seneca1.txt'
file2 = 'seneca2.txt'
file3 = 'seneca3.txt'
string1 = 'First Line\nSecond Line\nThird Line\n'
list1 = ['Line 1', 'Line 2', 'Line 3']
lab5b.append_file_string(file1, string1)
lab5b.read_file_string(file1)
# Will return 'First Line\nSecond Line\nThird Line\nFirst Line\nSecond Line\nThird Line\n'
lab5b.write_file_list(file2, list1)
lab5b.read_file_string(file2)
# Will return 'Line 1\nLine 2\nLine 3\n'
lab5b.copy_file_add_line_numbers(file2, file3)
lab5b.read_file_string(file3)
# Will return '1:Line 1\n2:Line 2\n3:Line 3\n'
- Download the checking script and check your work:
cd ~/ops435/lab5/ pwd #confirm that you are in the right directory ls CheckLab5.py || wget http://ops345.ca/ops445/CheckLab5.py python3 ./CheckLab5.py -f -v lab5b
- Before proceeding, make certain that you identify all errors in lab5b.py. When the checking script tells you everything is OK - proceed to the next step.
Exceptions and Error Handling
Every programmer and every program runs into errors all the time. You should expect that it will happen for any code that you write. In Python, when an error occurs, the python runtime raises an exception. This section will teach you to catch these exceptions when they happen and to allow the program to continue running, or to stop program execution with a readable error message.
There exists a massive number of exceptions. If you write a lot of a certain type of code: you'll become familiar with the exceptions the methods you typically use throw. Online references can be useful for new-to-you methods. You also have an option to not handle exceptions at all (as you did so far in this course), but your resulting program may not be acceptable, depending on where and how it's used.
In this section, we will provide examples of how to handle a few exceptions in Python.
- To start, create a new temporary python program. Before attempting to handle exception errors, let's create an error, and then see how to can "handle" it:You should get an exception error similar to the following:
print("5" + 10)
--------------------------------------------------------------------------- Traceback (most recent call last) Fiel "<stdin>", line 1, in <module> TypeError: Can't convert 'int' object to str implicitly
- Click on the link [1] and scroll down to TypeError. You've seen this error before so you already know what the problem is, but take a couple of minutes to read the documentation. It will be hard to understand what they're talking about, but this sort of exercise is worth the time and effort.
If we don't want the user of our program to have to learn how to read Python exceptions (which is a very good idea), we can catch/trap/handle this exception when it happens. This is done with a specific block of code called a try clause where you place code in-between the try: and the except: coding blocks. In a general sense, it works like a modified if-else statement, where the try statement acts as a test, and the except statement will or will not handle the exception depending if it occurs or does NOT occur. That is to say, If no error occurs in the code contained in the try section, the script will continue as usual but if an error occurs in the "try" section, then it can be handled in whatever way you feel is appropriate (like an user-friendly error message).
Let's demonstrate handling our TypeError error with code that first does not contain an error and then similar code that DOES generate an error.
- The following code does NOT generate an error:
try: print(5 + 10) print("Still inside try block") except TypeError: print("At least one of the values is NOT an integer") print("End of program")
- The following code handles an exception error to provide user-friendly feedback that at least one of the values is not an integer:
try: print(5 + "ten") print("Still inside try block") except TypeError: print("At least one of the values is NOT an integer") print("End of program")
Walk through what happens in each of the two examples below. Notice that once an exception is thrown inside a try block: execution of the code stops, and jumps to the except block.
If an exception happens and it's not handled with try/except: your entire program will crash. That is by design, and is a good thing. You need to handle exceptional circumstances in your program, the computer can't do that for you.
Exceptions work the same way in all the programming languages that I've seen that have them, so the mechanics of handling exceptions is worth learning, even though it is a lot more code to write.
- Generate another type of error by attempting to open a file that doesn't exist:
f = open('filethatdoesnotexist', 'r') print("End of program")
- Now, catch and handle this exception:
try: f = open("filethatdoesnotexist", "r") print("This is right after the open() call.") f.close() except FileNotFoundError: print("Tried to open filethatdoesnotexist for reading but it doesn't exist.") print("End of program")
You can catch multiple exceptions at the same time, such as does not exist, is a directory, or we don't have permission.
- Try running the code below with different paths: a file that does not exist, a file which does exist but you don't have permissions to read, or a directory instead of a regular file:
try: f = open("filethatdoesnotexist", "r") f.close() except (FileNotFoundError, PermissionError, IsADirectoryError, IOError): print("Failed to open file") print("End of program")
- By taking the time to view the Python Exception Hierarchy, you can see how errors get caught in python. The options FileNotFoundError, PermissionError, and IsADirectory are all inherited from OSError. This means that while using more specific errors might be useful for better error messages and handling, if you can figure out what specific errors may happen to your code.
- Another way to catch multiple exceptions is with separate
except
bloks:try: f = open("abc", "r") f.close() except (FileNotFoundError, PermissionError): print("File does not exist or wrong permissions") except IsADirectoryError: print("File is a directory") except (OSError, IOError): print("Unable to open file") except: print("unknown error occured")
When catching multiple exceptions, make certain to catch the lowest ones contained in the exception-hierarchy first. For example, if you put 'Exception' first, both 'OSError' and 'FileNotFoundError', would never get caught.
TIP: In python it's usually best to 'try:' and 'except:' code rather than to attempt to anticipate everything that could go wrong with if statements. For example, instead of checking to see if a file exists and we have read permissions, it can be better to just try and read the file and fail and catch any errors with 'OSError'.
Practice Handling Exceptions
- Create the ~/ops435/lab5/lab5c.py program. Use the following as a template:
#!/usr/bin/env python3 def add(number1, number2): # Add two numbers together, return the result, in case of an exception: # return the string 'error: could not add numbers' def read_file(filename): # Read a file, return a list of all lines, in case of an exception: # return the string 'error: could not read file' if __name__ == '__main__': print(add(10,5)) # works print(add('10',5)) # works print(add('abc',5)) # exception print(read_file('seneca2.txt')) # works print(read_file('file10000.txt')) # exception
Sample Run 1:
python3 lab5c.py
15
15
error: could not add numbers
['Line 1\n', 'Line 2\n', 'Line 3\n']
error: could not read file
Sample Run 2 (with import):
import lab5c
lab5c.add(10,5)
# 15
lab5c.add('10',5)
# 15
lab5c.add('10','5')
# 15
lab5c.add('abc','5')
# 'error: could not add numbers'
lab5c.add('hello','world')
# 'error: could not add numbers'
lab5c.read_file('seneca2.txt')
# ['Line 1\n', 'Line 2\n', 'Line 3\n']
lab5c.read_file('file10000.txt')
# error: could not read file'
- Download the checking script and check your work:
cd ~/ops435/lab5/ pwd #confirm that you are in the right directory ls CheckLab5.py || wget http://ops345.ca/ops445/CheckLab5.py python3 ./CheckLab5.py -f -v lab5c
- Before proceeding, make certain that you identify any and all errors in lab5c.py. When the checking script tells you everything is OK before proceeding to the next step.
Submit evidence of your work
Run the following command in a terminal:
cd ~/ops435/lab5
python3 ./CheckLab5.py -f
- The output of the lab check command must say OK.
- To show that you completed the lab, submit a screenshot of the terminal with that output.