Chapter 7: Error Raising and Handling - VinGok/Python-Basics GitHub Wiki

** Exception Handling Python indicates errors and exceptional conditions by raising exceptions, although some third-party Python libraries use more old-fashioned techniques, such as “error” return values. The built-in exception classes can be subclassed to define new exceptions; programmers are encouraged to derive new exceptions from the Exception class or one of its subclasses, and not from BaseException. More information on defining exceptions is available in the Python Tutorial under User-defined Exceptions.

*** Catching and Raising Exceptions

try:
   try_suite
except exception_group1 as variable1:
   except_suite1
...
except exception_groupN as variableN:
   except_suiteN
else:
   else_suite
finally:
   finally_suite

->>> while True print('It is True')
SyntaxError: invalid syntax
->>> 
Raising new exception

->>>raise new_exc from original_exc
e.g
raise ValueError('A very specific bad thing happened')

There must be at least one except block, but both the else and the finally blocks are optional. The else block’s suite is executed when the try block’s suite has finished normally—but it is not executed if an exception occurs. If there is a finally block, it is always executed at the end. Each except clause’s exception group can be a single exception or a parenthesized tuple of exceptions. For each group, the as variable part is optional; if used, the variable contains the exception that occurred, and can be accessed in the exception block’s suite. If an exception occurs in the try block’s suite, each except clause is tried in turn. If the exception matches an exception group, the corresponding suite is executed. To match an exception group, the exception must be of the same type as the (or one of the) exception types listed in the group, or the same type as the (or one of the) group’s exception types’ subclasses. For example, if a KeyError exception occurs in a dictionary lookup, the first except clause that has an Exception class will match since KeyError is an (indirect) subclass of Exception . If no group lists Exception (as is normally the case), but one did have a LookupError , the KeyError will match, because KeyError is a subclass of LookupError . And if no group lists Exception or LookupError , but one does list KeyError , then that group will match.

->>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
->>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
->>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

->>> try:
-	10/0
-except ZeroDivisionError:
-	print("Zero division forbidden")

	
Zero division forbidden

->>> try:
-	10/0
-except Exception:
-	print("Zero division forbidden")

	
Zero division forbidden
->>> 

->>> try:
-	10/0
-except Exception as err:
-	print(err.args)

	
-('division by zero',)

In Python 3, you can chain Exceptions, which preserve tracebacks:

->>> raise RuntimeError('specific message') from error

->>> if 0 < distance <= RADIUS:
    #Do something.
->>> elif RADIUS < distance:
    #Do something.
->>> else:
+    raise AssertionError("Unexpected value of 'distance'!", distance)

*** Traceback This method sets tb as the new traceback for the exception and returns the exception object. It is usually used in exception handling code like this:

try:
    ...
except SomeException:
    tb = sys.exc_info()[2]
    raise OtherException(...).with_traceback(tb)

->>> import sys, traceback
->>> def run_user_code(envdir):
-    source = input(">>> ")
-    try:
-        exec(source, envdir)
-    except:
-        print("Exception in user code:")
-        print("-"*60)
-        traceback.print_exc(file=sys.stdout)
-        print("-"*60)

->>> envdir = {}
->>> while True:
-	    run_user_code(envdir)

	    
+>>> def another_function():
-Exception in user code:
+------------------------------------------------------------
+Traceback (most recent call last):
+  File "<pyshell#8>", line 4, in run_user_code
+  File "<string>", line 1
+    def another_function():
                          ^
+SyntaxError: unexpected EOF while parsing
+------------------------------------------------------------
->>> pi()
+Exception in user code:
+------------------------------------------------------------
+Traceback (most recent call last):
+  File "<pyshell#8>", line 4, in run_user_code
+  File "<string>", line 1, in <module>
+NameError: name 'pi' is not defined
+------------------------------------------------------------
+>>> import math
+>>> math.pi()
+Exception in user code:
+------------------------------------------------------------
+Traceback (most recent call last):
+  File "<pyshell#8>", line 4, in run_user_code
+  File "<string>", line 1, in <module>
+TypeError: 'float' object is not callable
+------------------------------------------------------------
+>>> 

Choose right exception or more common

->>> a=[1,2,3]
->>> try:
-	print(a[5])
-except IndexError as err:
-	print(err.args)

	
('list index out of range',)
->>> try:
-	print(a[5])
-except Exception as err:
-	print(err.args)

	
('list index out of range',)
->>> try:
-	print(a[5])
-except ValueError as err:
-	print(err.args)

	
Traceback (most recent call last):
  File "<pyshell#65>", line 2, in <module>
    print(a[5])
IndexError: list index out of range
->>> try:
-	print(a[5])
-except LookupError as err:
-	print(err.args)

	
('list index out of range',)

->>> try:
-	print(a[5])
-except LookupError as err:
-	print("Be careful, the index is {}".format(err.args))

	
Be careful, the index is ('list index out of range',)

*** Nice exception-handling example

def read_data(filename):
    lines = []
    fh = None
    try:
       fh = open(filename, encoding="utf8")
       for line in fh:
           if line.strip():
               lines.append(line)
     except (IOError, OSError) as err:
        print(err)
        return []
     finally:
        if fh is not None:
           fh.close()
     return lines

***Raising exceptions Exceptions provide a useful means of changing the flow of control. We can take advantage of this either by using the built-in exceptions, or by creating our own, raising either kind when we want to. Examples

  1. raise exception(args)
  2. raise exception(args) from original_exception
  3. raise

When the third syntax is used, that is, when no exception is specified, raise will reraise the currently active exception—and if there isn’t one it will raise a TypeError .

*** Custom exceptions Custom exceptions are custom data types (classes). The syntax is

class exceptionName(baseException): pass

class FoundException(Exception): pass
try:
   for row, record in enumerate(table):
       for column, field in enumerate(record):
            for index, item in enumerate(field):
                if item == target:
                    raise FoundException()
except FoundException:
   print("found at ({0}, {1}, {2})".format(row, column, index))
else:
   print("not found")

*** More error types together

More see [[http://stackoverflow.com/questions/2052390/manually-raising-throwing-an-exception-in-python][here]] Description of all exceptions see [[https://docs.python.org/3/library/exceptions.html#bltin-exceptions][here]]

⚠️ **GitHub.com Fallback** ⚠️