admin管理员组

文章数量:815885

详解 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/0except NameError as n:print(n)
try:f()
except ZeroDivisionError as z:print(z)
division by zero
def f():try:return 3/0except NameError as n:print(n)finally:name1try: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('开始')breakexcept: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 zeroDuring 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     name25 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 rangeDuring 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:breakfinally:print('结束')
开始
结束
def f():    try:return '开始'finally:print('结束')
f() # 先执行 finally 再离开函数调用
结束'开始'

本文标签: 详解 try 语句