对象的基本内容学习的差不多了,现在开始学习关于异常和文件的知识。
异常
程序运行的时候报错,这个就叫异常,说白了就是pycharm编程的时候出的小红字。
常见错误类型有很多,语法错误SyntaxError、类型错误TypeError、缩进错误IndentationError、索引错误IndexError、值错误ValueError等等。一旦发生错误,程序将会立即终止,下面的代码会不再运行。
异常的处理
报错的目的是系统希望在出现异常的时候程序员可以及时处理,而不是为了停止程序。因此我们也可以写一些代码试一试可能报错的代码是不是真的会报错。语法是:
try:
(缩进符)可能出错的代码
except:
(缩进符)出错后的处理方式
else:
(缩进符)没出错时的命令(可以不写)
print('循环开始')
try:
for i in range(10):
print(1 / i)
except:
print('不可以')
print('循环结束')
显而易见这个循环会出错,因为range(10)从零开始取。
循环开始
不可以
循环结束
可以看到,这样就避免了程序的终止,同时表明程序循环部分的代码确实有问题。如果想在else上写点东西,也可以:
print('循环开始')
try:
for i in range(1,10):
print(1 / i)
except:
print('不可以')
else:
print('没问题')
print('循环结束')
循环开始
1.0
0.5
0.3333333333333333
0.25
0.2
0.16666666666666666
0.14285714285714285
0.125
0.1111111111111111
没问题
循环结束
异常的传播
报错的位置有两个:全局和函数里面。如果在函数里面有错,再在全局引用函数,就会报两个错误。 而且先报最外层,也就是最直接的错误,再往上回溯到根源错误。比如下面这个代码:
def baocuo():
for i in range(10):
print(1 / i)
(950行)baocuo()
他的报错如下,可见先报下面这个引用函数的错误,再报导致引用函数错误的函数内的错误。
也就是说,函数有问题的时候,如果像之前使用了try这样的处理方式处理可能异常的部分,那么异常将不会传播,也不会报错。但是如果没有进行处理,那么就好像上面这种一样,异常将向函数调用处传播(也就是从内往外传),多个函数嵌套调用同理,一层一层得向下一个调用处传播,直到到全局 。
程序运行过程中出现异常的时候,所有异常信息将会被保存到一个异常对象里面,异常传播的本质就是异常对象被调用处使用了。异常类型就是上面图的那个除零异常ZeroDivisionError,和之前说的语法错误SyntaxError等一个性质。这些异常类型的type都是类名是这个名字的类。
异常对象
获取异常对象的信息,其实可以用上面try语句里面的except,如果在‘except:’下面不加任何内容,那他会获取所有的异常。而如果将其改写为‘except 异常类型:’,他就会只获取写上去的异常类型。如果没有这个类型的异常,就会报错。
try:
for i in range(1,10):
print(1 / i)
except ZeroDivisionError:
print('不可以')
else:
print('没问题')
有没有这个筛选,对于有特定这个异常的语句,结果不会有什么区别,但是没有这个类型的异常的时候就会报错。如果写‘except Exception:’也会获取所有异常,因为这个是所有异常类型的父类。如果写成‘except Exception as 变量名:’,然后在下面打印这个变量,就能知道异常的内容或类型(打印type(变量名))了。
在else下面还能加一个finally语句,可以加入无论是否有异常都要执行的命令。
try:
for i in range(10):
print(1 / i)
except ZeroDivisionError:
print('不可以')
else:
print('没问题')
finally:
print('有没有错都会吱一声')
不可以
有没有错都会吱一声
另外注意,整个try语句里面只有except部分可以写好几个。
自定义异常对象
自己写代码也可以设计一些自己代码专属的异常,抛出给用户。语法就是raise 异常类型。
def jia(q,w): # 希望qw都为非负数,否则报错
if q < 0 or w < 0:
raise Exception
r = q + w
return r
jia(23,-9)
Traceback (most recent call last):
File "D:/4classcode/4classcode/lianxi.py", line 972, in <module>
jia(23,-9)
File "D:/4classcode/4classcode/lianxi.py", line 968, in jia
raise Exception
Exception
但是可以看到没有像系统报错一样‘异常类型:×××××××’有解释异常的内容这时候只要在异常类型后面加上(‘内容’)就行了。
def jia(q,w): # 希望qw都为非负数,否则报错
if q < 0 or w < 0:
raise Exception('有负数输入')
r = q + w
return r
jia(23,-9)
Traceback (most recent call last):
File "D:/4classcode/4classcode/lianxi.py", line 972, in <module>
jia(23,-9)
File "D:/4classcode/4classcode/lianxi.py", line 968, in jia
raise Exception('有负数输入')
Exception: 有负数输入
报错的目的是告诉用户代码有问题,需要用户结合自己那边的因素修复,这就是设置报错的意义。
如果不想用报错这种不友善的方式告诉用户,也可以return一些内容来提醒。
def jia(q,w): # 希望qw都为非负数,否则报错
if q < 0 or w < 0:
return None
r = q + w
return r
print(jia(23,-9))
None
但是如果不打印,这样甚至不能让用户知道错了,所以也有弊端。
我们还可以自定义异常类,只要创建一个类继承Exception就行。
class Fushucuowu(Exception):
pass
def jia(q,w): # 希望qw都为非负数,否则报错
if q < 0 or w < 0:
raise Fushucuowu
r = q + w
return r
jia(23,-9)
结果就是:
可以看到自定义的异常显示了出来。