Exception
Handle Exception
try:
	clause
except ExceptI as errorInfo:
	if ExceptI is raised, execute this block
except ExceptII as errorInfo:
	if ExceptII is raised, execute this block
except:
	handle any other exception
else:
	if no exception, execute this block
finally:
	this would always be executed
		
try:
   fh = open("testfile", "r")
   fh.write("This is my test file for exception handling!!")
except IOError as argument:
   print ("Error: can\'t find file or read data", argument)
else:
   print ("Written content in the file successfully")
   fh.close()
finally:
    print("End of try ... except ...")
		
try:
   fh = open("testfile", "r")
   raise ValueError('Value Error')
except IOError as argument:
    print ("Error: can\'t find file or read data\n", argument)
except Exception as err: # handle any exceptions
    print(err)
#except: # handle any exceptions
    #print ("Error: value error\n")
else:
    print ("Written content in the file successfully")
    fh.close()
finally:
    print("End of try ... except ...")
		
Raise Exception
raise Exception(errorInfo)
		
Python Exception Hierarchy
Raise and Handle
def div(a, b):
    if b == 0:
        raise ZeroDivisionError("Denominator is zero ...")
    return a/b
 
if __name__ == '__main__':
    try:
        div(1, 0)
    except Exception as err:
        print(err.args, err)
		
def div(a, b):
    assert b != 0, 'AssertionError: Divided by zero ...'
    return a/b

def main():
    try:
        div(1, 0)
    except Exception as err:
        print('Catch error in main ...')
        raise # relay exception
 
if __name__ == '__main__':
    try:
        main()
    except Exception as err:
        print(err.args, err)
		
assert
  • If the expression is false, Python raises an AssertionError exception
  • def div(a, b):
        assert b != 0, 'AssertionError: Divided by zero ...'
        return a/b
     
    if __name__ == '__main__':
        try:
            div(1, 0)
        except Exception as err:
            print(err.args, err)
    		
  • python -O Exception.py, turn off assertion
  • # Exception.py
     
    def getString():
        return "Hello World!"
     
    if __name__ == '__main__':
        s = getString()
        assert s == "Hello", "string is not correct ..."
        print(s) # Hello World!
    		
    Traceback
    import traceback
    
    def div(a, b):
        assert b != 0, 'AssertionError: Divided by zero ...'
        return a/b
     
    if __name__ == '__main__':
        try:
            div(1, 0)
        except Exception as err:
            print(err.args, err)
            traceback.print_exc()
    		
    User-Defined Exceptions
    class definedExcept(Exception):
        def __int__(self, arg):
            self.args = arg
     
    def div(a, b):
        if b == 0:
            raise definedExcept("Defined Exception ...")
        return a/b
     
    if __name__ == '__main__':
        try:
            div(1, 0)
        except Exception as err:
            print(err.args, err)
    		
    Exception Relay
  • If a function receive an Exception from its sub-function and has no exception handler, the exception is relay to its parent function
  • def f():
        raise Exception('Error in f ...')
        
    def f2():
        print('Start f2 ...')
        f()
        print('Content in f2 ...')
        
    try:
        f2()
    except Exception as err:
        print(err)
    
    # Error in f ...
            
    NotImplemented
  • If NotImplemented is returned, a reflection will be called
  • Should be returned by the binary special methods, e.g. __eq__(), __lt__(), __add__()
  • __radd__ is the reflection function of __add__, it will be used when left object has no __add__ or return NoImplemented
  • class MyAge(object):
        def __init__(self, n):
            self.n = n
            
        def __add__(self, other):
            if not isinstance(other, MyAge):
                print('Return NotImplemented')
                return NotImplemented
            self.n =self.n + other.n
            
        def __str__(self):
            return 'Age: %d' % self.n
    
    class MyCar(object):
        def __init__(self, year):
            self.year = year
            
        def __radd__(self, other):
            print('Call reflection ...')
            self.year = self.year + other.n
            
        def __str__(self):
            return 'Year: %d' % self.year
    
    a1 = MyAge(42)
    a2 = MyAge(41)
    
    a1+a2 # use __add__ of a1
    print(a1) # 83
    
    c1 = MyCar(10)
    a1 + c1 # use __radd__ of c1 since a1 return NoImplemented
    print(a1, c1) # 83, 93
            
  • __eq__ is the reflection function of another __eq__, no __req__
  • == call __eq__ of left object, then call __eq__ of right object if NoImplemented is returned
  • class MyAge:
        def __init__(self, n):
            self.n = n
            
        def __eq__(self, other):
            if not isinstance(other, MyAge):
                return NotImplemented
            return self.n == other.n
    
    class MyCar(object):
        def __init__(self, year):
            self.year = year
            
        def __eq__(self, other):
            print('Call reflection ...')
            return False
            
        def __str__(self):
            return 'Year: %d' % self.year
    
    a1 = MyAge(42)
    a2 = MyAge(42)
    
    a1 == a2 # __eq__ in MyAge, True
    
    c1 = MyCar(10)
    a1 == c1 # __eq__ in MyCar, False
            
    Reference