1, What is an exception
An exception is a signal of a program error. Once an error occurs in the program, an exception will be generated. If it is not handled in the program, an exception will be thrown, and the operation of the program will be terminated.
In Python, the exceptions triggered by errors are as follows:
There are two kinds of errors. One is syntax error, which should be corrected before the program runs:
>>> if File "<stdin>", line 1 if ^ SyntaxError: invalid syntax
The other is logic error, which can be modified as soon as possible after it occurs. Common logic errors are as follows:
# TypeError: numeric type cannot be added to string type 1 + '2' # ValueError: cannot convert to int type when the string contains a non numeric value num = input(">>: ") # Enter hello int(num) # NameError: a nonexistent name x is referenced x # IndexError: index exceeds the limit of the list lis = ['jason', 'tony'] lis[3] # KeyError: a nonexistent key is referenced dic = {'name': 'jason'} dic['age'] # AttributeError: the referenced attribute does not exist class Foo: pass Foo.x # ZeroDivisionError: divisor cannot be 0 1 / 0
2, Exception handling
In order to ensure the fault tolerance and reliability of the program, that is, there is a corresponding processing mechanism to prevent the program from crashing when encountering errors, we need to handle exceptions. The basic syntax format of processing is as follows:
try: Detected code block except Exception type: When an exception is detected, the logic of this location is executed
Examples are as follows:
try: print('start...') print(x) # A nonexistent name is referenced, and the exception NameError is triggered print('end...') except NameError as e: print('The outliers are:%s' % e) print('run other code...') """as Syntax assigns the value of an exception type to a variable e,So we print e You can know the cause of the error"""
The execution results are:
start... The outliers are: name 'x' is not defined run other code...
Once an exception occurs in the original program, it will end as a whole. After exception handling, when an exception occurs in the detected code block, the code after the exception location in the detected code block will not be executed. Instead, the except sub code block matching the exception will be executed, and the rest of the code will run normally.
When different types of exceptions may be triggered in the detected code block, for different types of exceptions:
If we want to use different logic processing, we need to use multi branch except (similar to multi branch elif, matching from top to bottom, and no other matching will be made once the matching is successful):
try: Detected code block except NameError: trigger NameError Processing logic corresponding to except IndexError: trigger IndexError Processing logic corresponding to except KeyError: trigger KeyError Processing logic corresponding to
Examples are as follows:
def convert_int(obj): try: res = int(obj) except ValueError as e: print('ValueError: %s' % e) res = None except TypeError as e: print('TypeError: %s' % e) res = None return res convert_int('jason') # ValueError: invalid literal for int() with base 10: 'jason' convert_int({'n': 1}) # TypeError: int() argument must be a string, a bytes-like object or a number, not 'dict'
If we want to handle multiple types of exceptions with one logic, we can put multiple exceptions into a tuple and match them with an exception:
try: Detected code block except (NameError, IndexError, TypeError): trigger NameError or IndexError or TypeError Processing logic corresponding to
Examples are as follows:
def convert_int(obj): try: res = int(obj) except (ValueError, TypeError): print('argument must be number or numeric string') res = None return res convert_int('eason') # argument must be number or numeric string convert_int({'n': 1}) # argument must be number or numeric string
If we want to catch all exceptions and handle them with one logic, Python provides a universal Exception exception:
try: Detected code block except NameError: trigger NameError Processing logic corresponding to except IndexError: trigger IndexError Processing logic corresponding to except Exception: Other types of exceptions are handled by the logic here
An else can be followed by a multi branch except (else must follow except and cannot exist alone). Only when the detected code block does not trigger any exceptions will the sub code block of else be executed:
try: Detected code block except Exception type 1: pass except Exception type 2: pass ...... else: No code block executed when an exception occurs
In addition, try can also be used with finally. Grammatically, finally must be placed after else, but you can use the form of try except finally or try finally directly;
Whether the detected code block triggers an exception or not, the finally sub code block will be executed. Therefore, some resource recycling operations are usually performed in the finally sub code block, such as closing the open file, closing the database connection, etc.
try: Detected code block except Exception type 1: pass except Exception type 2: pass ...... else: No code block executed when an exception occurs finally: A block of code that executes whether or not an exception occurs
Examples are as follows:
f = None try: f = open('db.txt', 'r', encoding='utf-8') s = f.read().strip() int(s) # If the string s contains a non number, the exception ValueError will be triggered f.close() """If the above code triggers an exception, it is impossible to execute the code here, and the operation of closing the file should be placed in the finally in""" finally: if f: # If the file exists, the value of f is not None f.close()
When it does not comply with the syntax or logic rules of the Python interpreter, it is various types of exceptions actively triggered by the Python interpreter. For violations of various rules customized by the programmer, the programmer needs to explicitly trigger the exception. This uses the raise statement. After raise, it must be an exception class or an exception instance:
class Student: def __init__(self, name, age): if not isinstance(name, str): raise TypeError('name must be str') if not isinstance(age, int): raise TypeError('age must be int') self.name = name self.age = age stu1 = Student(4573, 18) # TypeError: name must be str stu2 = Student('jason', '18') # TypeError: age must be int
When the built-in exception is not enough, we can define the exception class by inheriting the built-in exception class:
You can define a new Exception by inheriting Exception:
class PoolEmptyError(Exception): def __init__(self, value = 'The proxy source is exhausted'): # The initialization method can be customized super(PoolEmptyError, self).__init__() self.value = value def __str__(self): # You can define this method to customize the format of printing exception values when an exception is triggered return '< %s >' % self.value class NetworkIOError(IOError): # You can also extend a related exception based on a specific exception pass raise PoolEmptyError # __main__.PoolEmptyError: < The proxy source is exhausted > raise NetworkIOError('connection not permitted') # __ main__.NetworkIOError: connection denied
Finally, Python also provides an assertion statement assert expression, which determines that the expression expression is true, otherwise an exception AssertionError will be triggered, which has the same semantics as raise if not, as follows:
age = '18' # If the return value of the expression isinstance(age, int) is False, an exception AssertionError is triggered assert isinstance(age, int) # Equivalent to if not isinstance(age, int): raise AssertionError
3, When to use exception handling
After understanding the exception handling mechanism, in order to improve the fault tolerance and reliability of the program, readers may mistakenly think that try... Exception... Should be added to the program as much as possible, which is actually over consuming the readability of the program, because try... Exception is originally an additional logic you add to the program, which has little to do with your main work.
If the condition of error occurrence is "predictable", we should use if to "prevent", as follows:
age = input('input your age>>: ').strip() if age.isdigit(): # It can be predicted that int(age) will not trigger an exception only if the string age is a number, age = int(age) else: print('You must enter the number')
If the condition of error occurrence is "unpredictable", that is, the exception must be triggered, then we should use the try...except statement to handle it.
For example, when we write a function to download web content, it is normal for exceptions such as network delay to occur, and we simply cannot predict what conditions will be met before the delay will occur, so we can only use the exception handling mechanism:
import requests from requests.exceptions import ConnectTimeout def get(url): try: response = requests.get(url, timeout=3) # If the download fails for more than 3 seconds, a ConnectTimeout exception will be triggered res = response.text except ConnectTimeout: print('Connection request timed out') res = None except Exception: print('Other network exceptions') res = None return res get('https://www.python.org')
Summary:
- The code that may have errors needs to be monitored;
- The less code to be monitored, the better;
- The lower the frequency of exception capture, the better;