Python学习

第九天

今天我们来说下Python中的异常,以及如何去处理异常。我们在程序编码中难免会碰到异常,今天我们就要来简要说明什么是异常,如何处理异常。

1、异常的定义

不论是Python语言、Java语言以及其他任何语言,程序在执行的过程中难免会产生的错误,这些错误都可以称之为异常。比如列表索引越界、打开不存在的文件等。
就如同下面两行代码:

print(str1)
# name 'str1' is not defined
open('error.txt','r')
# No such file or directory: 'error.txt'

2、异常处理

程序中出现异常是难免的,发生异常时我们需要捕获处理它,否则程序会终止执行。
如下代码:

#控制台输入两个数字 求商
print('程序开始')
num1 = int(input('请输入除数'))
num2 = int(input('请输入被除数'))
print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
print('程序结束')

上述这段代码其实就是存在问题的,比如我在获得数字num1的时候输入的内容不可以转换为int(比如你输入wasd),这个时候就出现异常了。
ValueError: invalid literal for int() with base 10: 'wasd'
其实就是将非数字字符串转换为整型出现的异常;
如果你在获得num2的时候,如果输入了0也会出现异常,
ZeroDivisionError: division by zero
其实就是除以0的原因导致的。
并且我们发现上述两种异常任何一种异常出现,我们的程序就停止了,并且程序没有往下执行,因为我们在控制台看不到最后一行print的输出。
这时候就需要我们异常处理了。

2.1、异常类

在Python中,所有异常都是基类Exception的成员,它们都定义在exceptions模块中。
如果这个异常对象没有进行处理和捕捉,程序就会用所谓的回溯(traceback,一种错误信息)终止执行,这些信息包括错误的名称(例如NameError)、原因和错误发生的行号。下面简单说下我们经常遇见的几个异常:
1、NameError
尝试访问一个未声明的变量,会引发NameError。

print(str1)
# NameError: name 'str1' is not defined

2、ZeroDivisionError
当除数为零的时候,会引发ZeroDivisionError异常。

a = 10/0
print(a)
# ZeroDivisionError: division by zero

**3、SyntaxError **
当解释器发现语法错误时,会引发SyntaxError异常。

a = 10
if a == 10
    print('宾果!')
# SyntaxError: invalid syntax

4、IndexError
当使用序列中不存在的索引时,会引发IndexError异常。

list = [1,2,3,4]
a = list[4]
print(a)
# IndexError: list index out of range

5、KeyError
当使用映射中不存在的键时,会引发KeyError异常。

mydict = {'name':'张三','age':18}
address = mydict['address']
print(address)
# KeyError: 'address'

**6、FileNotFoundError **
试图打开不存在的文件时,会引发FileNotFoundError。

file = open('a.txt','r')
# FileNotFoundError: [Errno 2] No such file or directory: 'a.txt'

7、AttributeError
当尝试访问未知对象属性时,会引发AttributeError异常。

class Settings():
   def _init_(self):
       self.scren_width=1200
       self.screen_height=800
       self.bg_color=(230,230,230)
if __name__ == '__main__':
   a = Settings()
   print(a.scren_width)
# AttributeError: 'Settings' object has no attribute 'scren_width'

2.2、异常处理

在python中,try-except语句定义了监控异常的一段代码,并提供了处理异常的机制。

1、捕获指定异常

try:
        # 可能会出现异常的语句块
except <异常种类>:
        # 异常处理代码
print('程序开始')
try:
    a = 10/0
    print(a)
except ZeroDivisionError as e:
    print('捕获异常-零不可以是除数',e)
print('程序继续执行')
# 程序开始
# 捕获异常-零不可以是除数 division by zero
# 程序继续执行

注意,exception后捕获的异常必须和try代码块中出现的异常种类一致,才可以捕获,否则依然会出现异常,影响其后代码的执行。

print('程序开始')
try:
    a = 10/0
    print(a)
except FileNotFoundError as e:
    print('捕获异常-文件找不到',e)
print('程序继续执行')
# ZeroDivisionError: division by zero

2、捕获多个异常

捕获多个异常有两种方式,第一种是一个except同时处理多个异常,不区分优先级。

try:
     # 可能会出现异常的语句块
except (<异常名1>, <异常名2>, ...): 
      # 异常处理代码
print('程序开始')
try:
   num1 = int(input('请输入除数'))
   num2 = int(input('请输入被除数'))
   print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
except (ZeroDivisionError,ValueError):
   print('出现异常了')
print('程序继续执行')

还有第二种方式,是区分优先级的。

try:
        # 可能会出现异常的语句块
except <异常种类1>:
        # 异常处理代码1
except <异常种类2>:
        # 异常处理代码2
except <异常种类3>:
        # 异常处理代码3
print('程序开始')
try:
   num1 = int(input('请输入除数'))
   num2 = int(input('请输入被除数'))
   print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
except ZeroDivisionError as e1:
   print('出现异常了',e1)
except ValueError as e2:
   print('出现异常了',e2)
print('程序继续执行')

3、异常中的else

如果try语句没有捕获到任何的错误信息,就不再执行任何except语句,而是会执行else语句。

try:
        # 可能会出现异常的语句块
except <异常种类1>:
        # 异常处理代码1
except <异常种类2>:
        # 异常处理代码2
except <异常种类3>:
        # 异常处理代码3
else:
    # try语句中没有异常则执行此段代码
import  os
print('程序开始执行')
try:
    wfile = open('2.txt','w',encoding='utf-8')
    wfile.write('这是测试文件写入的内容')
except IOError as e:
    print('IO异常',2)
else:
    print('内容写入成功')
    wfile.close()
print('程序继续执行')
# 程序开始执行
# 内容写入成功
# 程序继续执行

4、捕获所有的异常

当程序中出现大量异常时,捕获这些异常是非常麻烦的。这时,我们可以在except子句中不指明异常的类型,这样,不管发生何种类型的异常,都会执行except里面的处理代码。

print('程序开始')
try:
   num1 = int(input('请输入除数'))
   num2 = int(input('请输入被除数'))
   print(str(num1)+'除以'+str(num2)+'的结果是',str(num1/num2))
except:
   print('出现异常了')
print('程序继续执行')

5、终止行为(finally)

在程序中,无论是否捕捉到异常,都必须要执行某件事情,例如关闭文件、释放锁等,这时可以提供finally语句处理。通常情况下,finally用于释放资源。

str = 'hello python'
try:
    a = int(str)
except IndexError as e1:
    print('出现异常',e1)
except KeyError as e2:
    print('出现异常',e2)
except ValueError as e3:
    print('出现异常',e3)
else:
    print('try内没有异常')
finally:
    print('无论异常与否,都会执行我')

3、raise语句

python是否可以在程序的指定位置手动抛出一个异常?答案是肯定的,python 允许我们在程序中手动设置异常,使用 raise 语句即可。类似Java中的throw。
语法:raise [exceptionName [(reason)]]
其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。
简而言之就是使用raise语句能显示地触发异常。
格式如下:
1、raise 异常类名 引发指定异常类的实例
2、raise 异常类对象 引发指定异常类的实例
3、raise 重新引发刚刚发生的异常

3.1、使用类名引发异常

print('程序开始执行')
try:
    a = input('请输入一个数字')
    #判断用户输入的是否为数字
    if(not a.isdigit()):
        raise ValueError("输入的必须是数字") #人为扔出异常
except ValueError as e:
    print("引发异常:",repr(e))
print('程序继续执行')
# 程序开始执行
# 请输入一个数字wasd
# 引发异常: ValueError('输入的必须是数字')
# 程序继续执行

3.2、使用异常类的实例引发异常

print('程序开始执行')
try:
    a = input('请输入一个数字')
    #判断用户输入的是否为数字
    if(not a.isdigit()):
        err = ValueError()
        raise err
except ValueError as e:
    print("引发异常:",repr(e))
print('程序继续执行')

3.3、raise传递异常

不带任何参数的raise语句,可以再次引发刚刚发生过的异常,作用就是向外传递异常。

print('程序开始执行')
try:
    a = input('请输入一个数字')
    #判断用户输入的是否为数字
    if(not a.isdigit()):
        raise ValueError("输入的必须是数字")
except ValueError as e:
    print("引发异常:",repr(e))
    raise
print('程序继续执行')
# ValueError: 输入的必须是数字

4、assert语句

assert语句又称作断言,指的是期望用户满足指定的条件。
当用户定义的约束条件不满足的时候,它会触发AssertionError异常,所以assert语句可以当做条件式的raise语句。
assert语句格式如下:
assert 逻辑表达式,data
相当于:
if not 逻辑表达式:
raise AssertionError(data)
assert后面紧跟一个逻辑表达式,相当于条件。Data通常是一个字符串,当条件为false时作为异常的描述信息。

print('程序开始执行')
a = int(input('请输入除数'))
assert a != 0,'除数不可以为0'
# AssertionError: 除数不可以为0

5、自定义异常

python允许我们自定义异常,只需要两步:
1、创建一个继承Exception类的子类,就是自定义异常类。
2、当遇到自己设定的错误时,使用raise语句抛出自定义的异常。

#自定义异常类
class MyErr(Exception):
    def __init__(self,args):
        self.args = args
#触发自定义异常
if __name__ == '__main__':
    print('程序开始执行')
    try:
        raise MyErr('这是我自定义的异常')
    except MyErr as e:
        print('出现的异常为',e.args)

6、总结

这次主要针对Python的异常进行介绍,包括异常类、抛出和捕捉系统内置的异常、抛出和捕捉自定义异常,大家应该深入了解了异常产生的原理,并知道如何在程序中运行它们。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容