This exercise for the 2017 Spring
Quarter Foundations of Programming: Python course,
demonstrates and explains Python's exception handling and pickling features.
In this article, I go through a short explanation of each of these items.
Exception Handling
Python uses the Try/Except construct to enable a coder to provide clear explanations and corresponding corrective instructions to utilize when errors happen. The Try/Except construct at its most basic level enables a developer to identify and handle conditions that break the code in a program. This video provides a clear, concise walkthrough of Try/Except. The narrator in the video notes that when Python encounters an error it presents a standard error type with an accompanying message. Here is an example of such an error message:
Traceback (most recent call last):
File "script.py",
line 62, in <module>
lstItems = inputs(list)
File "script.py",
line 57, in inputs
first_number = int(input("Enter the
first number:"))
ValueError: invalid
literal for int() with base 10: 'text'
The yellow-highlighted text shows an output that occurred during the execution of the script.py program where a user entered the word "text" instead of the integer number that program was expecting as indicated by the red-highlighted code snippet. Now, this error makes sense to a coder but may not be clear to someone without such coding background. For both the non-coder or another programmer who must in the future support the system where this code exists, making a clearer, more informative error message available will improve the readability of program and its future supportability.
The ValueError type is one of many built-in exceptions available in Python. Alternatively, this list provides concise descriptions of some of the more common exceptions provided in the built-in exception list.
Let's now improve the code to produce more informative error messages. Consider the code shown below that produced the error noted earlier.
# Take two numbers and demonstrate some errors
def inputs():
'''
:param: None
:return: list comprised of two
numbers generated in this function.
'''
first_number = int(input("Enter the first number:"))
second_number = int(input("Enter the second number: "))
return [first_number, second_number] #
package results into a list and return to main program.
# MAIN
lstItems = inputs() # generate list using inputs
function
first,second = lstItems[0],lstItems[1] # assign variables to list elements
# Some operations:
division_result = first/second # perform division
multiplication_result = first*second # perform
multiplication
print("Division result:",division_result)
print("Multiplication result:", multiplication_result)
This
code in the 'MAIN' section calls a function that in turn takes two inputs, first_number and second_number from
the user and then performs division and multiplication operations with those
numbers. The previous error occurred when 'text' was entered at the first
prompt instead of an integer. Here is the standard Python error be if zero was
entered for second_number:
Traceback
(most recent call last):
File "script.py", line 66, in <module>
division_result = first/second
ZeroDivisionError:
division by zero
In
these two error examples two exception types, ValueError (noted
earlier) and ZeroDivisionError occur. Since two different conditions cause
these respective exception types to be indicated -- 'raised' in Python terms --
the code is modified as follows to handle each condition:
try:
def
inputs():
'''
:param: None
:return: list
comprised of two numbers generated in this function.
'''
first_number
= int(input("Enter
the first number:"))
second_number = int(input("Enter the second number: "))
return
[first_number, second_number] #
package results into a list and return to main program.
# MAIN
lstItems
= inputs() # generate list using inputs function
first,second
= lstItems[0],lstItems[1] # assign variables to list elements
# Some operations:
division_result
= first/second # perform division
multiplication_result
= first*second # perform multiplication
print("Division
result:",division_result)
print("Multiplication
result:", multiplication_result)
except ValueError:
# Handle situations where something
other than an integer is entered.
print("You
entered something other than an integer number. Please try again.")
except ZeroDivisionError:
# Handle cases where '0' is entered in
the second number input.
print("You
entered a zero for your second number. That is not permitted. Please try
again.")
Observe
now what the program reports if (1) something other than an integer is entered
for one of those numbers, and (2) zero is entered for the second number:
(1) Non-integer
Input:
/anaconda/bin/python
/Volumes/C/_PythonClass/script.py
Enter the
first number:1
Enter the
second number: text
You
entered something other than an integer number. Please try again.
Process
finished with exit code 0
(2) Zero
entered for the second number:
/anaconda/bin/python
/Volumes/C/_PythonClass/script.py
Enter the
first number:4
Enter the
second number: 0
You
entered a zero for your second number. That is not permitted. Please try again.
Process
finished with exit code 0
Note
that both of these error messages are clearer -- and a bit friendlier -- than
the default messages that Python generates.
The
next section goes discusses Python's pickling feature.
Pickling
Python
uses the pickle module as the documentation notes to "serializ[e] and de-serializ[e] a Python object structure". Serialization, as discussed in various ways here, here, and in a particularly-helpful description here, is used in
Python and other languages for tasks that involve preserving a state of an
object for later use by the same program or invoked by another one elsewhere. Examples
where this capability is important include saving a state of a game program, or as discussed in this article saving a
complex structure utilized in a trained, machine learning algorithm. Pickling
in particular is useful because of its speed advantage in loading a 'pickled'
data set compared to reading in the same data from a database or in another
format such as JSON.
How
does pickle work? It takes an input like a tuple, list, or a dictionary,
and writes the input to a binary file structure. When the contents of
that binary file are later wanted, pickle opens the binary, loads it for use in
subsequent processing.
Here
is a simple example of pickling in which a dictionary that contains airlines
and some of the aircraft models they operate is picked into a binary file.
The dictionary is pickled into a binary file, carriers.dat, the file is
closed, the file is reopened, the content is retrieved into a new dictionary,
and the contents of that dictionary are then printed to screen.
import pickle #
Load the pickle module# Build a dictionary of some airlines and some models
they fly.dctAirlinesModels = {"Alaska": "737", "Delta": "A320", "SkyWest": "E175LR", "Air Canada": "787"}
# Place the dictionary's contents into a binary
file:pickle_out = open("carriers.dat", "wb") # open a binary file
for writingpickle.dump(dctAirlinesModels, pickle_out) # places the dctAirlinesModels dictionary
into the carriers.dat filepickle_out.close()
# Retrieve the contents of the binary filepickle_retrieve = open("carriers.dat", "rb") # open binary file in
read modeairline_models = pickle.load(pickle_retrieve) # load the contents into the
airline_models dictionarypickle_retrieve.close() # done retrieving carriers.dat
contents. Close the binary file
# Display the contents of the airline_models
dictionaryprint("Airline Model\n=========== ==========") # Header for display
of airline_modelsfor airline in airline_models:
print("{0:<11s} {1:<10s}".format(airline, airline_models[airline])) # formatted for
printing
The
output printed to screen is:
/anaconda/bin/python
/Volumes/C/_PythonClass/Assignment07_try_pickling.py
Airline Model
===========
==========
Alaska 737
Delta A320
SkyWest E175LR
Air
Canada 787
The
contents of the carriers.dat file is:
� }q(X Alaskaq X 737q X Deltaq X A320q X SkyWestq X
E175LRq X
Air Canadaq X 787q u.
Note
that at best the entries are obfuscated. As noted many places in the
documentation and in tutorial files, pickling does not encrypt contents.
Other approaches like this one demonstrated using PyCrypto perform
file-encryption tasks.
Summary
This
post showed a couple of examples to demonstrate how exception handling and
pickling work in Python. These examples plus the referenced
documentation, linked examples, and tutorial videos should provide enough
material to get started using these features.