Skip to main content

Section 13.2 Runetime Stack and raise command

There are cases where the sequential flow-of-control does not work well. An example will best explain this.
Let’s suppose that a program contains complex logic that is appropriately subdivided into functions. The program is running and it currently is executing function D, which was called by function C, which was called by function B, which was called by function A, which was called from the main function. This is illustrated by the following simplistic code example:
def main()
  A()

def A():
  B()

def B():
  C()

def C():
  D()

def D()
  # processing
Function D determines that the current processing won’t work for some reason and needs to send a message to the main function to try something different. However, all that function D can do using normal flow-of-control is to return a value to function C. So function D returns a special value to function C that means “try something else”. Function C has to recognize this value, quit its processing, and return the special value to function B. And so forth and so on. It would be very helpful if function D could communicate directly with the main function (or functions A and B) without sending a special value through the intermediate calling functions. Well, that is exactly what an exception does. An exception is a message to any function currently on the executing program’s “run-time-stack”. (The “run-time-stack” is what keeps track of the active function calls while a program is executing.)
In Python, your create an exception message using the raise command. The simplest format for a raise command is the keyword raise followed by the name of an exception. For example:
raise ExceptionName
So what happens to an exception message after it is created? The normal flow-of-control of a Python program is interrupted and Python starts looking for any code in its run-time-stack that is interested in dealing with the message. It always searches from its current location at the bottom of the run-time-stack, up the stack, in the order the functions were originally called. A try: except: block is used to say “hey, I can deal with that message.” The first try: except: block that Python finds on its search back up the run-time-stack will be executed. If there is no try: except: block found, the program “crashes” and prints its run-time-stack to the console.
Let’s take a look at several code examples to illustrate this process. If function D had a try: except: block around the code that raised a MyException message, then the flow-of-control would be passed to the local except block. That is, function D would handle it’s own issues.
def main()
  A()

def A():
  B()

def B():
  C()

def C():
  D()

def D()
  try:
    # processing code
    if something_special_happened:
      raise MyException
  except MyException:
    # execute if the MyException message happened
But perhaps function C is better able to handle the issue, so you could put the try: except: block in function C:
def main()
  A()

def A():
  B()

def B():
  C()

def C():
  try:
    D()
  except MyException:
    # execute if the MyException message happened

def D()
  # processing code
  if something_special_happened:
    raise MyException
But perhaps the main function is better able to handle the issue, so you could put the try: except: block in the main function:
def main()
  try:
    A()
  except MyException:
    # execute if the MyException message happened

def A():
  B()

def B():
  C()

def C():
  D()

def D()
  # processing code
  if something_special_happened:
    raise MyException
You have attempted of activities on this page.