Example: raising an exception

def get_ratios(L1, L2):
""" Assumes: L1 and L2 are lists of equal length of numbers
    Returns: a list containing L1[i]/L2[i] """
  ratios = []
  for index in range(len(L1)):
    try:
      ratios.append(L1[index]/L2[index])
    except ZeroDivisionError:
      ratios.append(float('nan')) #nan = not a number
    except:
      raise ValueError('get_ratios called with bad arg') #manage flow of program by raising own error
    return ratios

get_ratios("") #will raise ValueError.  Can enclose this within an except block
Notice that an exception searches for the innermost try/except block. If it does not exist in the current function, it exits the function (destroying its scope) and going to the caller's scope, caller's caller's scope, and so on, until a try/except block is found. If no try/except block is found, the program terminates and the user is shown the details of the exception raised.

Example: We are given a class list for a subject, such that each list entry is a list of two parts:

marks = [ [ ['rahul', 'tendulkar'], [80.0, 70.0, 85.0] ],
          [ ['sachin', 'dravid'], [100.0, 80.0, 74.0] ] ]
Create a new class list, with name, marks, and an average
[ [ ['rahul', 'tendulkar'], [80.0, 70.0, 85.0], 78.33333 ],
  [ [ 'sachin', 'dravid'], [100.0, 80.0, 74.0], 84.66667 ] ]

Example code

def get_stats(class_list):
  new_stats = []
  for elt in class_list:
    new_stats.append([elt[0], elt[1], avg(elt[1])])
  return new_stats

def avg(marklist):
  return sum(marklist)/len(marklist)

We will get an error on the following input:

marks = [ [ ['rahul', 'tendulkar'], [80.0, 70.0, 85.0] ],
          [ [ 'sachin', 'dravid'], [100.0, 80.0, 74.0] ],
          [ ['test'], [] ] ]
Get ZeroDivisionError: float division by zero because try to divide by len(marklist) which is 0 for test.

Multiple choices for handling these errors using except:

Assertions

Assertions as defensive programming

Where to use assertions?

Example:

cube = int(input("Enter a number: ")
for guess in range(abs(cube)+1):
  assert(guess**3 <= abs(cube))
  if guess**3 >= abs(cube):
    break
  assert(guess**3 < abs(cube))
if guess**3 != abs(cube):
  print(cube, 'is not a perfect cube')
else:
  if cube < 0:
    guess = -guess
  print('Cube root of ' + str(cube) + ' is ' + str(guess))
Another example:
cube = int(input("Enter a number: ")
epsilon = 0.01
low = 0
high = cube
guess = (low+high)/2.0
num_guesses = 0
while abs(guess**3 - cube) >= epsilon:
  assert(low <= guess)
  assert(guess <= high)
  if guess**3 < cube:
    low = guess
  else:
    high = guess
  guess = (high + low)/2.0
  num_guesses += 1
print 'num_guesses =', num_guesses
print(guess, 'is close to the cube root of', cube)

Example on longest common subsequence (LCS):

def isCommonSubsequence(X, Y, R):
  xi = 0
  yi = 0
  for c in R:
    while X[xi] != c:
      xi+=1
      if xi == len(X):
        return False
    while Y[yi] != c:
      yi+=1
      if yi == len(Y):
        return False
  return True

def lcs(X, Y):
  ret = ""
  if len(X) == 0 or len(Y) == 0:
    ret = ""
  elif X[-1] == Y[-1]:
    lcsXY = lcs(X[0:-1], Y[0:-1])
    ret = lcsXY + X[-1]
  else:
    lcsY = lcs(X[0:-1], Y)
    lcsX = lcs(X, Y[0:-1])
    if len(lcsY) < len(lcsX):
      ret = lcsX
    else:
      ret = lcsY
  assert(isCommonSubsequence(X, Y, ret))
  return ret

Example on placing N queens in an NxN chessboard

global N
N = 4

def printSolution(board):
    for i in range(N):
        for j in range(N):
            if board[i][j] == 1:
                print("Q",end=" ")
            else:
                print(".",end=" ")
        print()

def isSafe(board, row, col):

    # Check this row on left side
    for i in range(col):
        if board[row][i] == 1:
            return False

    # Check upper diagonal on left side
    for i, j in zip(range(row, -1, -1),
                    range(col, -1, -1)):
        if board[i][j] == 1:
            return False

    # Check lower diagonal on left side
    for i, j in zip(range(row, N, 1),
                    range(col, -1, -1)):
        if board[i][j] == 1:
            return False

    return True


def solveNQUtil(board, col):
    # Base case: If all queens are placed
    # then return true
    if col >= N:
        return True

    # Consider this column and try placing
    # this queen in all rows one by one
    for i in range(N):

        if isSafe(board, i, col):

            # Place the queen at board[i][col]
            board[i][col] = 1

            # Recurse to place rest of the queens
            if solveNQUtil(board, col + 1) == True:
                return True

            board[i][col] = 0

    return False

def solveNQ():
    board = [[0, 0, 0, 0],
             [0, 0, 0, 0],
             [0, 0, 0, 0],
             [0, 0, 0, 0]]

    if solveNQUtil(board, 0) == False:
        print("Solution does not exist")
        return False

    for i in range(0, N, 1):
      for j in range(0, N, 1):
        assert (!board[i][j] || isSafe(board, i, j))
    printSolution(board)
    return True