错误和异常
一、错误
错误分为语法错误和逻辑错误
1.语法错误
>>> if
File "<stdin>", line 1
if
^
SyntaxError: invalid syntax
程序执行过程中,python解释器会检测你的程序是否存在语法错误,如果程序出错python解释器会指出出错的一行,并且在最先找到的 错误的文职标记了一个小小的箭头。
2.逻辑错误
>>> 1/0Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
二、异常
即便python的程序的语法是正确的,在运行它的时候,也有可能发生错误,程序运行期检测到的错误被称为异常。
异常是有错误产生的。
程序出现了异常都不会被程序处理,都以错误信息的会展现出来。
>>> 1/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4+"xi"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> li = [1,2,3,4]
>>> li[1]
2
>>> li[10]
Traceback (most recent call last): #Trackback,追溯到最近的错误信息
File "<stdin>", line 1, in <module>
IndexError: list index out of range #IndexError 异常类 冒号后面是异常的值
异常都有不同的类型出现,这些错误类型都作为信息的一部分打印出来,例子中的类型有ZeroDivisionError,TypeError,IndexError。每一种错误类型,都有相应的异常类。
1.python中的异常类
在python中不同的异常可以用不同的类型(类型即类)去标识,不同的类的对象标识了不同的异常,一个异常标识一种错误。
python中所有的错误都是从BaseException类派生的
BaseException # 所有异常的基类
+-- SystemExit # 解释器请求退出
+-- KeyboardInterrupt # 用户中断执行(通常是输入^C)
+-- GeneratorExit # 生成器(generator)发生异常来通知退出
+-- Exception # 常规异常的基类
+-- StopIteration # 迭代器没有更多的值
+-- StopAsyncIteration # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
+-- ArithmeticError # 各种算术错误引发的内置异常的基类
| +-- FloatingPointError # 浮点计算错误
| +-- OverflowError # 数值运算结果太大无法表示
| +-- ZeroDivisionError # 除(或取模)零 (所有数据类型)
+-- AssertionError # 当assert语句失败时引发
+-- AttributeError # 属性引用或赋值失败
+-- BufferError # 无法执行与缓冲区相关的操作时引发
+-- EOFError # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
+-- ImportError # 导入模块/对象失败
| +-- ModuleNotFoundError # 无法找到模块或在在sys.modules中找到None
+-- LookupError # 映射或序列上使用的键或索引无效时引发的异常的基类
| +-- IndexError # 序列中没有此索引(index)
| +-- KeyError # 映射中没有这个键
+-- MemoryError # 内存溢出错误(对于Python 解释器不是致命的)
+-- NameError # 未声明/初始化对象 (没有属性)
| +-- UnboundLocalError # 访问未初始化的本地变量
+-- OSError # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
| +-- BlockingIOError # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
| +-- ChildProcessError # 在子进程上的操作失败
| +-- ConnectionError # 与连接相关的异常的基类
| | +-- BrokenPipeError # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
| | +-- ConnectionAbortedError # 连接尝试被对等方中止
| | +-- ConnectionRefusedError # 连接尝试被对等方拒绝
| | +-- ConnectionResetError # 连接由对等方重置
| +-- FileExistsError # 创建已存在的文件或目录
| +-- FileNotFoundError # 请求不存在的文件或目录
| +-- InterruptedError # 系统调用被输入信号中断
| +-- IsADirectoryError # 在目录上请求文件操作(例如 os.remove())
| +-- NotADirectoryError # 在不是目录的事物上请求目录操作(例如 os.listdir())
| +-- PermissionError # 尝试在没有足够访问权限的情况下运行操作
| +-- ProcessLookupError # 给定进程不存在
| +-- TimeoutError # 系统函数在系统级别超时
+-- ReferenceError # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
+-- RuntimeError # 在检测到不属于任何其他类别的错误时触发
| +-- NotImplementedError # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
| +-- RecursionError # 解释器检测到超出最大递归深度
+-- SyntaxError # Python 语法错误
| +-- IndentationError # 缩进错误
| +-- TabError # Tab和空格混用
+-- SystemError # 解释器发现内部错误
+-- TypeError # 操作或函数应用于不适当类型的对象
+-- ValueError # 操作或函数接收到具有正确类型但值不合适的参数
| +-- UnicodeError # 发生与Unicode相关的编码或解码错误
| +-- UnicodeDecodeError # Unicode解码错误
| +-- UnicodeEncodeError # Unicode编码错误
| +-- UnicodeTranslateError # Unicode转码错误
+-- Warning # 警告的基类
+-- DeprecationWarning # 有关已弃用功能的警告的基类
+-- PendingDeprecationWarning # 有关不推荐使用功能的警告的基类
+-- RuntimeWarning # 有关可疑的运行时行为的警告的基类
+-- SyntaxWarning # 关于可疑语法警告的基类
+-- UserWarning # 用户代码生成警告的基类
+-- FutureWarning # 有关已弃用功能的警告的基类
+-- ImportWarning # 关于模块导入时可能出错的警告的基类
+-- UnicodeWarning # 与Unicode相关的警告的基类
+-- BytesWarning # 与bytes和bytearray相关的警告的基类
+-- ResourceWarning # 与资源使用相关的警告的基类。被默认警告过滤器忽略。
三、异常处理
程序出现了错误,肯定需要去进行异常处理。
什么是异常处理:
python解释器检测到错误,触发异常。
程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)
如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理
为何进行异常处理:
谁会用一个报错的程序,更何况使用者又不知道怎么解决,一运行就报错,谁用你的程序或则软件。
所以就必须提供一种异常处理机制来完善程序的容错性。
如何解决异常处理?
异常是有程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正。
在以前学程序的时候,经常使用if判断来做异常解决。
但是:
1.if判断是的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误需要些重复的if来进行处理。
2.在程序中频繁的写与程序本身无关,与异常处理有关的if,这样代码的可读性非常的差。
1.异常的捕获
基本语法
try:
可能会抛出异常的代码块
except:
捕获到异常后的处理代码
finally:
程序不论抛出异常还是没有抛出异常后要执行的代码,一般用于文件资源释放,内存回收等操作
2.错误类型捕获异常
基础语法
try:
需要捕获异常的代码
except 异常1:
捕获异常1,需要做的处理
except (错误2,异常3...):
捕获异常2、3,需要做的处理
finally:
程序最终需要执行的代码
通过日志查看错误的类型
代码示例:
try:
num = int(input("请输入一个整数,求结果:"))
print(100/num)
except ZeroDivisionError:
print('0不能做除数!')
except ValueError:
print('请输入一个正确的整数!')
finally:
print('欢迎下次使用!')
运行结果:
请输入一个整数,求结果:0
0不能做除数!
欢迎下次使用!
3.捕获未知错误
基础语法
try:
需要捕获异常的代码
except (错误1,异常2...):
捕获异常1、2,需要做的处理
except Exception as result:
捕获到未捕获的异常,可以 print("捕获到异常 %s" % result)
finally:
程序最终需要执行的代码
代码示例:
try:
num = int(input("请输入一个整数,求结果:"))
print(100/num)
except ValueError:
print('请输入一个正确的整数!')
except Exception as result:
print('捕获到异常%s' % result)
finally:
print('欢迎下次使用!')
运行结果:
请输入一个整数,求结果:0
捕获到异常division by zero
欢迎下次使用!
4.异常捕获完整代码
基础语法
try:
需要捕获异常的代码
except 异常1:
捕获异常1,需要做的处理
except (错误2,异常3...):
捕获异常2、3,需要做的处理
except Exception as result:
捕获到未捕获的异常,可以 print("捕获到异常 %s" % result)
else:
没有捕获到异常会执行的代码
finally:
程序最终需要执行的代码
5.异常的传递
——当代码或者函数传递出现错误抛出异常,会将异常传递给函数的调用方,一直传递到主程序
——如果主程序任没有对异常处理,程序将会报错并终止
——在开发中,异常的捕获可以放在主程序中,不需要每一个函数逐一的编写
def demo1():
print(10 / 0)
def demo2():
demo1()
try:
demo2()
except Exception as result:
print("捕获到异常 %s" % result)
运行结果:
捕获到异常 division by zero
四、抛出异常
raise 语句允许程序员强制发生指定的异常。例如:
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: HiThere
raise 唯一的参数就是要抛出的异常。这个参数必须是一个异常实例或者是一个异常类(派生自 Exception 的类)。如果传递的是一个异常类,它将通过调用没有参数的构造函数来隐式实例化:
raise ValueError # shorthand for 'raise ValueError()'
如果你需要确定是否引发了异常但不打算处理它,则可以使用更简单的 raise 语句形式重新引发异常
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flew by!')
... raise
...
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: HiThere
1.手动抛出 raise 异常
——用户可以根据业务需要主动抛出异常,一般用在检测业务输入逻辑的工具类中
应用场景
def check_psd(psd):
if len(psd) < 6:
raise Exception("密码长度必须大于6位!")
if len(psd) > 12:
raise Exception("密码长度必须小于12位!")
def input_psd():
return input("请输入密码:\n")
while True:
try:
psd = input_psd()
check_psd(psd)
print('密码输入正确')
except Exception as result:
print('%s' % result)
运行结果
请输入密码:
12345
密码长度必须大于6位!
请输入密码:
123456
密码输入正确
请输入密码:
12345678945612
密码长度必须小于12位!
请输入密码:
2.自定义异常类
应用场景
class myException(Exception):
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s0 = int(input("请输入最小长度:"))
s1 = input("请输入字符串:")
if len(s1) < s0:
raise myException(len(s1), s0)
except AttributeError:
print("对象没有这个属性")
except myException as ex:
print("抛异常:输入长度:{}, 不抛异常的最小长度:{}".format(ex.length, ex.atleast))
else:
print("没有抛异常")
运行结果
请输入最小长度:6
请输入字符串:6
抛异常:输入长度:1, 不抛异常的最小长度:6