详解 try 语句

try 语句

try 语句可为一组语句指定异常处理器和/或清理代码。语法结构有两种如下。

  • 有 try 和 except 子句(可多个),以及可选的 else 和 finally 子句:
try:
    suite
except expression as identifier:
    suite
else: # 可选
    suite
finally: # 可选
    suite
  • 只有 try 和 finally 子句:
try:
    suite
finally:
    suite

except 子句之后的表达式(通常为异常)expression,关键字 as 以及指定的别名 identifier 都是可选的。

当 try 子句中没有发生异常时,没有异常处理器会被执行。当 try 子句中发生异常时,将启动对异常处理器的搜索。此搜索会依次检查 except 子句,直至找到与该异常相匹配的子句。

except 子句可指定一个或多个异常,如果与发生的异常 “兼容” 则该子句将匹配该异常。

  • 指定的异常如果是发生的异常所属的类或基类,则该子句将匹配该异常;
  • 指定的异常可以置于一个元组,其中包含有与发生的异常 “兼容” 的异常,该子句将匹配该异常。

当一个异常完全未被处理时,解释器会终止程序的执行。

for i in range(3):
    try:
        print(3/i)
    except (ZeroDivisionError, AssertionError) as e:
        print(e)
division by zero
3.0
1.5
for i in range(3):
    try:
        print(3/i)
    except ZeroDivisionError:
        print(f'i={i}引发异常')
i=0引发异常
3.0
1.5
for i in range(3):
    print(3/i)
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-5-ddbcfc1a1b1b> in <module>
      1 for i in range(3):
----> 2     print(3/i)


ZeroDivisionError: division by zero

如果存在无表达式的 except 子句,它必须是最后一个,它将匹配任何异常:

try:
    3/0
except NameError as n:
    print(n)
except:
    pass

如果没有 except 子句与异常相匹配,则会在周边代码和发起调用栈上继续搜索异常处理器,除非存在一个finally 子句正好引发了另一个异常。新引发的异常将导致旧异常的丢失:

def f():
    try:
        return 3/0
    except NameError as n:
        print(n)
try:
    f()
except ZeroDivisionError as z:
    print(z)
division by zero
def f():
    try:
        return 3/0
    except NameError as n:
        print(n)
    finally:
        name1
        
try:
    f()
except ZeroDivisionError as z: # 该异常已丢失
    print(z)
except NameError as n:
    print(n)
name 'name1' is not defined

使用 as 将匹配的异常赋值给一个别名,才能在 except 子句之后引用它,并且它将在 except 子句结束时被清除:

for i in range(3):
    try:
        print(3/i)
    except (ZeroDivisionError, AssertionError) as e:
        print(e)
print(e)
division by zero
3.0
1.5



---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-16-a87e190baccb> in <module>
      4     except (ZeroDivisionError, AssertionError) as e:
      5         print(e)
----> 6 print(e)


NameError: name 'e' is not defined

如果控制流离开 try 子句体时没有引发异常,并且没有执行 return, continue 或 break 语句,可选的 else 子句将被执行:

try:
    print('开始')
except:
    print('捕获')
else:
    print('结束')
开始
结束
while True:    
    try:
        print('开始')
        break
    except:
        print('捕获')
    else:
        print('结束')
开始

如果存在 finally,它用来指定一个 “清理” 处理程序。try,except 或 else 子句中发生任何未处理的异常,会被临时保存。finally 始终被执行,被保存的异常,它会在 finally 子句执行后被重新引发:

try:
    print(3/0)
except:
    name2
else: # 未被执行
    range(3)[5]
finally:
    print('end')
end



---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-24-7d6fe0d94043> in <module>
      1 try:
----> 2     print(3/0)
      3 except:


ZeroDivisionError: division by zero


During handling of the above exception, another exception occurred:


NameError                                 Traceback (most recent call last)

<ipython-input-24-7d6fe0d94043> in <module>
      2     print(3/0)
      3 except:
----> 4     name2
      5 else: # 未被执行
      6     range(3)[5]


NameError: name 'name2' is not defined

如果 finally 子句引发了另一个异常,被保存的异常会被设为新异常的上下文。如果 finally 子句执行了 return, break 或 continue 语句,则被保存的异常会被丢弃:

while True:    
    try:
        print('开始')
    except:
        print('捕获')
    else:
        range(3)[5]
    finally:
        print(3/0)
开始



---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-25-1f272bfbd667> in <module>
      6     else:
----> 7         range(3)[5]
      8     finally:


IndexError: range object index out of range


During handling of the above exception, another exception occurred:


ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-25-1f272bfbd667> in <module>
      7         range(3)[5]
      8     finally:
----> 9         print(3/0)


ZeroDivisionError: division by zero
while True:    
    try:
        print('开始')
    except:
        print('捕获')
    else:
        range(3)[5]
    finally:
        break
开始

当 return, break 或 continue 语句在 finally 语句之前被执行时,finally 子语句也会 ‘在离开时’ 被执行:

while True:    
    try:
        print('开始')
    except:
        print('捕获')
    else:
        break
    finally:
        print('结束')
开始
结束
def f():    
    try:
        return '开始'
    finally:
        print('结束')
f() # 先执行 finally 再离开函数调用
结束





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

推荐阅读更多精彩内容