Philosophy of Python exception handling

0. Introduction

Work, Yiyanbuge between programmers bright codes, after all, whether the code itself or its execution, there will be no ambiguity, not ambiguous and can be described as the official language of the code between programmers. But its logic or algorithms deal with the problem is not the case.

I still remember two programmers swordfight are:

Asked one: late in the project have removed all of exception handling, an unknown exception occurs on the line after not allowed to put your exception handling here removed and replaced if else;

Asked two: Why here to exception handling? The code you write, how abnormal will happen?

This is my personal experience, do not know how we met these two questions will be answered, at least I was actually speechless. These two questions were asked by a senior Internet giant in a senior development and QA for different problems at different times.

Putting aside right or wrong, after all, the point of departure to consider the issue of different people are different. But from such a firm answer to exception handling at least one thing is certain, and that is a lot of people are too confident of their own code or code that is aware of the potential problems of intuition is not enough, let alone deal with potential problems in order to ensure the correct important business process flow logic. If you write the code simply consider normal circumstances, that is poison to the code.

I took the class this blog will follow the routine the cards (to avoid Ctrl + W), introduce the concept of specific operations and exception handling of python.

1. Why exception handling

The program is nothing more than common bug on two categories:

  • Grammatical errors;
  • Logic is not rigorous logic error or confusion caused;

The second error is obviously more difficult to detect, and the consequences are often more serious. No matter what kind of bug, waiting for us there are two consequences: First, the program collapse out; Second, the results do not meet expectations;

For some important key to perform the operation, exception handling can control program executed in a controlled range, of course, the premise is handled properly.

Or use a third party such as API API provided by us to third parties. In most cases the situation to correct an error processing the caller's call parameters and return abnormal results, or it may be made a scapegoat.

Running uncontrolled environment program, exception handling is a must. However, where the difficulty is when an exception occurs, how to deal with.

2. python exception handling

Below gradually introduce python exception handling related concepts.

2.1 Exception handling structure

Necessary structures for the try ... except, there is at least one except, else, and finally optional.

try:
    code blocks
except (Exception Class1, Exception Class2, ...) as e:
    catch and process exception
except Exception ClassN:
    catch and process exception
... ...
else:
    when nothing unexpected happened
finally:
    always executed when all to end

2.2 python type of built-in exceptions

Module contains all the built-in exceptions inheritance exception type, type the following:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |        +-- WindowsError (Windows)
      |    |        +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |        +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |        +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
          +-- DeprecationWarning
          +-- PendingDeprecationWarning
          +-- RuntimeWarning
          +-- SyntaxWarning
          +-- UserWarning
          +-- FutureWarning
      +-- ImportWarning
      +-- UnicodeWarning
      +-- BytesWarning

2.3 except clause

The wording used excpet clause as follows:

  • except: # default catch all types of exceptions
  • except Exception Class: # Capture Exception Class type of exception
  • except Exception Class as e: # Capture Exception Class type of exception, the exception object assigned to e
  • except (Exception Class1, Exception Class2, ...) as e: # capture any type of exception list

The above exception class python may be built following exception type may be custom exception types.

2.4 Abnormal matching principle

  • All except one matched clause in order to match the success of the follow-up is ignored except clause;
  • If the object is a thrown exception types derived object type of an object except clause exception given or given, the matching is successful;
  • If all except clauses have the match fails, an exception will be passed up;
  • If you still are not any try ... except to capture, before the program terminates calls sys.excepthook processing;

2.5 else & finally

If no exception occurs, and there is an else clause, the else clause is executed. As long as there is finally clause Under no circumstances it will be executed.

Probably the only place that is difficult to understand finally. No abnormalities, abnormal capture, upload and abnormal abnormal abnormal processing etc. will be executed finally statement.

The following look at an example:

Division DEF (A, B):
    the try:
        print'res% S = '% (A / B)
    the except (the ZeroDivisionError, ArithmeticError) AS E:
        return STR (E) used herein is # Note return
    the else:
        Print'% S / S% S =% '% (A, B, A / B)
    the finally:
        Print' the finally clause '

 Are input parameters (1, 2), (1, 0) and (1, "0") to perform:

print 'return value: %s' % division(a, b)

The results obtained were as follows:

res = 0
/ 2 = 0
finally clause
return value: None

finally clause
return value: integer division or modulo by zero

finally clause
Traceback (most recent call last):
  File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 217, in <module>
    print 'return value: %s' % division(1, "0")
  File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 208, in division
    print'res = %s' % (a / b)
TypeError: unsupported operand type(s) for /: 'int' and 'str'

Even if the program can be seen abnormal and is not handled correctly before the program terminates, finally statement is still being carried out. This program can be seen as the last effective security barrier. Mainly some remedial clean-up work, such as resource release, disconnect from the network and so on. Of course, with declarations can automatically help us to do some clean-up work.

2.6 raise an exception is thrown

During program execution can be used actively raise the throw. 

try:
    e = Exception('Hello', 'World')
    e.message = 'Ni Hao!'
    raise e
except Exception as inst:
    print type(inst), inst, inst.args, inst.message

结果:<type 'exceptions.Exception'> ('Hello', 'World') ('Hello', 'World') Ni Hao!

Args except above shows the properties of objects, message.

2.7 custom exception

Built-in types of anomalies in most cases been able to meet the usual development use, if you want a custom exception type can be inherited directly built-in types to achieve.

class ZeroDivZeroError(ZeroDivisionError):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self)
    def __repr__(self):
        return self.value

try:
    # do something and find 0 / 0
    raise ZeroDivZeroError('hahajun')
except ZeroDivZeroError as err:
    print 'except info %s' % err

Custom exception should be directly inherited from the Exception class or subclass, rather than inherited from BaseException.

3. Stack Trace

Python exception occurred during the execution, it will tell us where in the end the problem and what the problem occurs. These two types of error message are stack trace and exception, were used in the program and the exception object traceback object represented.

Traceback (most recent call last):
  File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 270, in <module>
    1 / 0
ZeroDivisionError: integer division or modulo by zero

The above error message contains an error occurs when the current stack information (stack trace, the first three rows) and exception information (exception, the last line), were stored in traceback objects and exception object thrown in.

The exception object and exception information has been introduced earlier, then we look at when an exception occurs, stack trace processing.

Traceback objects represent a stack trace of an exception. A traceback object is created when an exception occurs.

Then there are two cases:

  1. The exception is try ... except capture
  2. It is not caught or simply not processed

Normal code execution, may be used traceback.print_stack () output current call stack information procedure.

3.1 catch the exception

 For the first case are two ways to obtain the following stack trace information:

trace_str = traceback.format_exc()
Or the information acquired from the sys.exc_info captured () object or the like abnormal, then formatted into trace information.

get_trace_str DEF (Self):
    "" "
    Get except the abnormality information is captured from the stack frame or the previous frame in the current stack;
    not passed to try abnormality except sys.excepthook directly captured
    " ""
    T, V, TB = the sys.exc_info ()
    trace_info_list traceback.format_exception = (T, V, TB)
    trace_str = '' .join (trace_info_list)

As exception object thrown contains exception information can be acquired except Exception class as e try ... except in the structure. 

3.2 uncaught exception

The second case, if the exception is not handled or uncaught sys.excepthook will be called before the launch of the program will output traceback and exception information to sys.stderr.

def except_hook_func(tp, val, tb):
    trace_info_list = traceback.format_exception(tp, val, tb)
    trace_str = ' '.join(trace_info_list)
    print 'sys.excepthook'
    print trace_str
sys.excepthook = except_hook_func

Custom function above except hook instead sys.excepthook function. The exception type tp in the hook function, outliers and traceback tb objects acquired stack trace. In this case an exception can not get information from sys.exc_info in.

3.3 Test

def except_hook_func(tp, val, tb):
    trace_info_list = traceback.format_exception(tp, val, tb)
    trace_str = ' '.join(trace_info_list)
    print 'sys.excepthook'
    print trace_str
sys.excepthook = except_hook_func
try:
    1 / 0
except TypeError as e:
    res = traceback.format_exc()
    print "try...except"
    print str(e.message)
    print res

Taking sys.excepthook processing flow results:

sys.excepthook
Traceback (most recent call last):
   File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 259, in <module>
    1 / 0
 ZeroDivisionError: integer division or modulo by zero

The except TypeError as e changed except ZeroDivisionError as e, then taking the try ... except capture abnormal process results are as follows:

try...except
integer division or modulo by zero
Traceback (most recent call last):
  File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 259, in <module>
    1 / 0
ZeroDivisionError: integer division or modulo by zero

4. Abnormal information collection

Talk so much, we look at how to implement a program to collect information on the trace.

class TracebackMgr(object):

    def _get_format_trace_str(self, t, v, tb):
        _trace = traceback.format_exception(t, v, tb)
        return ' '.join(_trace)

    DEF handle_one_exception (Self):
        "" "
        Get exception information except captured from the stack frame or the previous stack frame currently in;
        is not the try except caught exceptions will automatically use handle_traceback collected
        " ""
        T, V, TB = SYS .exc_info ()
        self.handle_traceback (T, V, TB, False)

    handle_traceback DEF (Self, T, V, TB, is_hook = True):
        "" "
        Alternatively sys.excepthook this function to automatically collect not try ... except uncaught exception,
        the use of exception handling try except to manually call the above function handle_one_exception it possible to assemble
        "" "
        trace_str self._get_format_trace_str = (T, V, TB)
        self.record_trace (trace_str, is_hook)
        # do something the else

    def record_trace(self, trace_str, is_hook):
        # Do somethind
        print 'is_hook: %s' % is_hook
        print trace_str

Its usage is very simple:

trace_mgr = TracebackMgr()
sys.excepthook = trace_mgr.handle_traceback
try:
    1 / 0
except Exception as e:
    trace_mgr.handle_one_exception()
    # process trace

1 / '0'

The results collected two trace information in two ways:

is_hook: False
Traceback (most recent call last):
   File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 299, in <module>
    1 / 0
 ZeroDivisionError: integer division or modulo by zero

is_hook: True
Traceback (most recent call last):
   File "D:\My Folders\Cnblogs\Alpha Panda\Main.py", line 304, in <module>
    1 / '0'
 TypeError: unsupported operand type(s) for /: 'int' and 'str'

 You can redirect the standard input and output, and error log will print information into the file:

class Dumpfile(object):
    @staticmethod
    def write(str_info):
        with open('./dump_file.txt', 'a+') as fobj:
            fobj.write(str_info)

    def flush(self):
        self.write('')
sys.stdout = sys.stderr = Dumpfile()

trace collection mainly uses two things: how to capture the abnormal collection of information under abnormal and in both cases, are introduced earlier.

5. Summary

python exception handling:

  1. Represented by objects exception error message, each to a corresponding class are abnormal, showing the base class for all BaseException exception handling classes.
  2. During program execution exception matching exception class and all of its base class corresponding to the object is thrown.
  3. Exception classes can be defined by the built-in type of exception class is derived.
  4. Caught exception can be thrown again.
  5. If you can make use of the built-in alternatives, such as if getattr (obj, attr_name, None), or with other structures.
  6. the sys.exc_info () save stack frame prior to the current stack frame is acquired or try, except abnormality information captured.
  7. Cause an unhandled exception will be processed before the program terminates sys.excpethook can customize defined sys.excpethook.

Abnormal trap:

Exception handling can make the correct code is more robust, but the wrong use exception too far.

Handle catch the exception but ignored or wrong is not desirable. Exception handling abuse not only fail to improve the effect of system stability, but also hidden away incentives that caused the error, resulting in increased difficulty to troubleshoot the problem.

Therefore more important than how to catch exceptions that should be how to deal with when an exception occurs.

Guess you like

Origin www.linuxidc.com/Linux/2020-02/162396.htm
Recommended