在写python代码的过程当中可能会出现一些错误,这些错误可区分为2类:语法错误 和 异常~html
>>> a = 2 >>> if a > 0 print('OK'); File "<stdin>", line 1 if a > 0 print('OK'); ^ SyntaxError: invalid syntax
如上语句即 存在语法错误,if 语句的条件后面没有冒号 ‘:’。
语法错误也称为解析错误,这类错误在程序执行以前就会被Python解释器检测到。若是使用IDE工具开发(例如 pycharm),pycharm会直接使用下标的红线提示开发者这里存在语法错误。这类错误必须在程序运行前就改正~python
代码不存在语法错误,在运行过程当中出现的逻辑错误,即为异常~mysql
>>> 1 / 0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> >>> >>> lst = ['a', 'b', 'c'] >>> lst[2] 'c' >>> lst[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
程序在运行过程当中,一旦发生异常,且发生的异常没有被捕获或者处理,则程序就会中止运行。
异常有不一样的类型,在发生异常时,异常的类型及发生异常的缘由 会被打印出来。上述示例中,第一个异常为 ZeroDivisionError(除数不能为0),第二个异常为 IndexError(列表指针超出范围)。
ZeroDivisionError 和 IndexError 都为Python的内置异常,即 python解释器 已经定义好的异常类型,常见的内置异常还有:StopIteration,GeneratorExit,AssertionError,EOFError,IOError,OSError等等。关于Python的内置异常及说明可参阅:https://docs.python.org/zh-cn/3.7/library/exceptions.html#bltin-exceptions
sql
这些内置异常都继承于Exception类(自定义的异常通常也是直接或间接地继承自Exception类),且全部 内置异常的名称都存在于 内置名称空间中,可直接使用,而不须要 'import exceptions模块'。数据库
try...except... 语句用于捕获异常 及 对异常的处理。这样程序在发生异常时,可针对性的作出处理,避免程序的中断~,try...except... 语句的语法以下:express
try: 可能发生异常的语句块 except [异常类型1]: 处理异常1的语句 except [异常类型2]: 处理异常2的语句
示例:ide
try: a = 1/0 except ZeroDivisionError: print('除数不能为0')
try...except... 语句的工做原理以下:函数
try: num = int(input("Enter a number: ")) # 这里可能会发生 ValueError 异常 a = 1/0 except ZeroDivisionError: print('除数不能为0')
对于可能会先发生的 ValueError 异常,异常类型和 except 关键字后面的异常不匹配,那么这个 异常 将不会被 这个except 捕获,因而这个异常就会被传递到外部~,结果输出以下:工具
Enter a number: abc Traceback (most recent call last): File "...test.py", line 9, in <module> num = int(input("Enter a number: ")) # 这里可能会发生 ValueError ValueError: invalid literal for int() with base 10: 'abc'
这个时候,可使用多个 except 来捕获异常:指针
try: num = int(input("Enter a number: ")) # 这里可能会发生 ValueError a = 1/0 except ZeroDivisionError: print('除数不能为0') except ValueError: print('请输入数字~') # 结果输出: Enter a number: abc 请输入数字~
固然也可使用一个万能异常 Exception 来处理。因为内置异常和自定义异常都直接或间接地继承自 Exception,因此 Exception 能够用来匹配任何异常。这样作的优点在于 能够针对全部的异常统一进行捕获,缺点在于 不能针对指定的异常作出相应的处理,而是统一使用一种方式进行处理~
try: num = int(input("Enter a number: ")) a = 1/0 except Exception: pass
在实际的应用中,通常这两种方式会被结合使用:针对指定的那么几个异常分别进行捕获并作相应的处理,剩下的全部异常都统一使用 Exception 来捕获~
try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print(err) except ValueError: print("数据类型没法转换") except Exception: print('Unexpected error')
最后的 Exception异常名 也能够省略不写(默认就是 Exception )
except: print('Unexpected error')
异常发生时,都会有关于这个异常的具体描述信息,异常的描述信息可经过 as 关键字获取,这个在上述示例中已经有使用~
try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print(err) # 若文件不存在,或有以下输出: [Errno 2] No such file or directory: 'myfile.txt'
else 为可选字句,放在 except 字句后面,若 try 语句块中没有异常发生,则会执行else 语句块中的代码~
try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print(err) else: f.close() # try 语句块正常执行完成后,关闭打开的文件
finally 也为可选字句,放在全部语句块的最后。无论 try 语句块中是否触发异常,都会执行 finally 语句块中的代码。finally 语句块中的代码通常都用于 关闭系统资源,例如关闭文件,关闭数据库链接等~
def connDB(): try: conn = pymysql.connect(host=HOST, user=USER, password=PASSWD, database=DATEBASE, charset='utf8', cursorclass=pymysql.cursors.DictCursor) return conn except Exception: logger.error("can not connect to database!") exit() db = connDB() try: ... pass except: ... pass finally: db.close()
在操做文件时,还可使用 with...as... 语句来自动关闭文件,即无论 with语句块 中是否触发异常,with语句块执行完毕后都会自动关闭文件~
try: f = open('myfile.txt', mode='r') a = 1/0 except Exception: print(f.closed) # False,当 try语句块中发生异常,文件没有被关闭 ############## try: with open('myfile.txt', mode='r') as f: a = 1 / 0 except Exception: print(f.closed) # True,文件已经自动关闭
raise语句用于手动触发异常,触发的异常能够经过传递参数说明异常的缘由,例如:
>>> raise IndexError('lst out of range') Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: lst out of range
在 except语句块中,若不想对捕获的异常进行处理,则可使用 raise语句 从新触发异常,由外层的 try语句来进行处理~
try: raise ZeroDivisionError('abc') except ZeroDivisionError: print('除数为0') raise # 更简单的写法,从新触发捕获到的异常
assert语法:
assert expression
assert 关键字根据后面的表达式的真假来肯定程序是否继续往下执行。若表达式返回为True,则程序继续往下执行,若为False,则触发 AssertionError 异常~
print('start...') assert 1 == 1 print('end...') # 输出结果: start... end... ################ print('start...') assert 1 == 2 print('end...') # 输出结果: start... Traceback (most recent call last): File ".../test.py", line 17, in <module> assert 1 == 2 AssertionError
经过继承 Exception 类来建立自定义的异常;自定义异常应该尽可能保持异常类的简单,通常自定义异常仅用于提取特有的错误信息~。自定义异常示例以下:
class MyError(Exception): def __init__(self, ErrorInfo): Exception.__init__(self) self.errorinfo=ErrorInfo def __str__(self): return self.errorinfo
注意:自定义的异常类只能经过 raise关键字 来手动触发。
使用 traceback 关键字追踪异常,须要导入 traceback 模块(import traceback)。
import traceback try: f = open('myfile.txt', mode='r') a = 1/0 except Exception: traceback.print_exc() logger.error(traceback.format_exc()) #使用日志模块记录 异常的详细信息,或使用 traceback.print_exc(file=path) 记录到指定文件 # 输出信息以下: Traceback (most recent call last): File "/Users/luyi/PycharmProjects/untitled/day26/test.py", line 12, in <module> a = 1/0 ZeroDivisionError: division by zero
这里异常信息的输出和不捕获异常时候系统的输出一致,其实 traceback.print_exc() 函数调用了sys.exc_info() 函数来完成 异常信息的输出,traceback.print_exc()的源码以下:
def print_exc(limit=None, file=None): """Shorthand for 'print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback, limit, file)'. (In fact, it uses sys.exc_info() to retrieve the same information in a thread-safe way.)""" if file is None: file = sys.stderr try: etype, value, tb = sys.exc_info() # 调用了 sys.exc_info() 函数 print_exception(etype, value, tb, limit, file) finally: etype = value = tb = None
.................^_^