第9章 异常try...except...else...finally

9.1 异常是什么

Python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象未被处理(或捕获)时,程序将终止并显示一条错误信息(traceback)。

>>>1 / 0
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ZeroDivisionError: division by zero

9.2 让事情沿你指定的轨道出错

1. 使用raise引发异常

>>>raise Exception
Traceback (most recent call last):
  File "<input>", line 1, in <module>
Exception
>>>raise Exception('hyperdrive overload')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
Exception: hyperdrive overload
>>>raise ArithmeticError
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ArithmeticError
一些内置的异常类
类名描述
Exception几乎所有的异常类都是从它派生而来的
AttributeError引用属性或给它赋值失败时引发
OSError操作系统不能执行指定的任务(如打开文件)时引发,有多个子类
IndexError使用序列中不存在索引时引发,为LookupError的子类
KeyError使用映射中不存在键时引发,为LookupError的子类
NameError找不到名称(变量)时引发
SyntaxError代码不正确时引发
TypeError将内置操作或函数用于类型不正确的变量时引发
ValueError将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适
ZeroDivisionError在除法或求模运算的第二个参数为零时引发

不是从Exception派生而来的异常类包括SystemExit和KeyboardInterrupt,因为它们是从BaseException(Exception的超类)派生而来的。 

 2. 自定义异常类(该类必须直接或间接的继承Exception)

class SomeCustomException(Exception): pass

9.3 捕获异常

>>>x = int(input('Enter the first number: '))
...y = int(input('Enter the second number: '))
...print(x / y)
Enter the first number: >? 10
Enter the second number: >? 0
Traceback (most recent call last):
  File "<input>", line 3, in <module>
ZeroDivisionError: division by zero

1. 抛出或处理异常捕获异常后,可以执行的操作:
         使用raise且不提供任何参数(也可显式地提供捕获到的异常)继续向上传播;
         处理异常(“抑制”异常);
         抛出其他异常;

class MuffledCalculator:
    def calc(self, expr):
        try:
            return eval(expr)
        except ZeroDivisionError:
            raise
class MuffledCalculator:
    def calc(self, expr):
        try:
            return eval(expr)
        except ZeroDivisionError:
            print('Division by zero is illegal')
class MuffledCalculator:
    def calc(self, expr):
        try:
            return eval(expr)
        except ZeroDivisionError:
            raise ValueError

抛出其他异常时(本例ValueError),导致进入except子句的异常(本例ZeroDivisionError)将被作为异常上下文存储起来,并出现在最终的错误消息中:

>>>try:
...    1 / 0
...except ZeroDivisionError:
...    raise ValueError
...
Traceback (most recent call last):
  File "<input>", line 2, in <module>
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "<input>", line 4, in <module>
ValueError

raise...from...语句用来提供自己的异常上下文或设置为None来禁用上下文

>>>try:
...    1 / 0
...except ZeroDivisionError:
...    raise ValueError from None
...
Traceback (most recent call last):
  File "<input>", line 4, in <module>
ValueError

2. 捕获多种异常 

多个except子句

try:
    x = int(input('Enter the first number: '))
    y = int(input('Enter the second number: '))
    print(x / y)
except ZeroDivisionError:
    print("The second number can't bu zero!")
except TypeError:
    print("That wasn't a number, was it?")

在一个元组中指定多种异常 

try:
    x = int(input('Enter the first number: '))
    y = int(input('Enter the second number: '))
    print(x / y)
except (ZeroDivisionError, TypeError, NameError):
    print('Your numbers were bogus ...')

 访问异常对象本身

try:
    x = int(input('Enter the first number: '))
    y = int(input('Enter the second number: '))
    print(x / y)
except (ZeroDivisionError, TypeError) as e:
    print(e)

 捕获所有类型异常:很危险不建议使用,包括将捕获用户使用Ctrl+C终止执行的企图、调用函数sys.exit来终止执行的企图。

多数情况下使用except Exception as e并对异常对象进行检查。

try:
    x = int(input('Enter the first number: '))
    y = int(input('Enter the second number: '))
    print(x / y)
except:
    print('Something wrong happened ...')

 3. else子句

在try代码块没有出现异常时执行else代码块中的内容

try:
    print('A simple task')
except:
    print('What? Something went wrong?')
else:
    print('Ah ... It went as planned.')
代码:
while True:
    try:
        x = int(input('Enter the first number: '))
        y = int(input('Enter the second number: '))
        value = x / y
        print('x / y is', value)
    except:
        print('Invalid input. Please try again.')
    else:
        break

执行:
Enter the first number: 1
Enter the second number: 0
Invalid input. Please try again.
Enter the first number: 'foo'
Invalid input. Please try again.
Enter the first number: baz
Invalid input. Please try again.
Enter the first number: 10
Enter the second number: 2
x / y is 5.0

使用except Exception as e

代码:
while True:
    try:
        x = int(input('Enter the first number: '))
        y = int(input('Enter the second number: '))
        value = x / y
        print('x / y is', value)
    except Exception as e:
        print('Invalid input:', e)
        print('Please try again.')
    else:
        break

执行:
Enter the first number: 1
Enter the second number: 0
Invalid input: division by zero
Please try again.
Enter the first number: 'x'
Invalid input: invalid literal for int() with base 10: "''"
Please try again.
Enter the first number: quuux
Invalid input: invalid literal for int() with base 10: 'quuux'
Please try again.
Enter the first number: 10
Enter the second number: 2
x / y is 5.0

4. finally子句

与try子句配套,无论try代码块发不发生异常,都将执行finally代码块,可用于在发生异常时执行清理工作,例如用于确保文件或网络套接字等得以关闭。

x = None
try:
    x = 1 / 0
finally:
    print('Cleaning up ...')
    del x

执行:
Cleaning up ...
Traceback (most recent call last):
  File "D:/pythonProject/Unit8.py", line 3, in <module>
    x = 1 / 0
ZeroDivisionError: division by zero

5. try...except...else...finally

try:
    1 / 0
except NameError:
    print("Unknown variable")
else:
    print("That went well!")
finally:
    print("Cleaning up.")

9.4 异常和函数

若函数中引发的异常得不到处理,将向上传播到调用函数的地方。如果在那里也未得到处理,异常将继续传播,直至到达主程序(全局作用域)。如果主程序中也没有异常处理程序,程序将终止并显示栈跟踪消息。

>>>def faulty():
...    raise Exception('Something is wrong')
...
>>>def ignore_exception():
...    faulty()
...    
>>>def handle_exception():
...    try:
...        faulty()
...    except:
...        print('Exception handled')
...        
>>>ignore_exception()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 2, in ignore_exception
  File "<input>", line 2, in faulty
Exception: Something is wrong
>>>handle_exception()
Exception handled

9.5 异常之禅

有时候,异常处理的实现方式比条件语句的实现方式有更好的可读性和更高的效率。

例子1:

条件语句实现方式,

def describe_person(person):
    print('Description of', person['name'])
    print('Age:', person['age'])
    if 'occupation' in person:
        print('Occupation:', person['occupation'])

实参字典中没有键occupation时,

Description of Throatwobbler Mangrove
Age: 42

实参字典中有键occupation时,

Description of Throatwobbler Mangrove
Age: 42
Occupation: camper

异常处理实现方式,

def describe_person(person):
    print('Description of', person['name'])
    print('Age:', person['age'])
    try:
        print('Occupation:', person['occupation'])
    except KeyError: pass

例子2:

try:
    obj.write
except AttributeError:
    print('The object is not writeable')
else:
    print('The object is writeable')

9.6 警告——不那么异常的情况

#使用warnings模块中的warn函数warn发出警告
>>>from warnings import warn
>>>warn("I've got a bad feeling about this.")
#警告只显示一次,如果再次运行最后一行代码,什么事情都不会发生

#使用warnings模块中的filterwarnings函数抑制警告(或特定类型的警告),并指定采取的措施,如"error"或"ignore"
>>>from  warnings import filterwarnings

>>>filterwarnings("ignore")
>>>warn("Anyone out there?")

>>>filterwarnings("error")
>>>warn("Something is very wrong!")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UserWarning: Something is very wrong!

#发出警告时,可以指定要引发的异常(即警告类别,默认UserWarning),但必须是Warning的子类。如果将警告转换为错误,将使用你指定的异常
>>>filterwarnings("error")
>>>warn("This function is really old...", DeprecationWarning)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
DeprecationWarning: This function is really old...
#根据异常来过滤特定类型的警告
>>>filterwarnings("ignore", category=DeprecationWarning)
>>>warn("Another deprecation warning.", DeprecationWarning)
>>>warn("Something else.")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UserWarning: Something else.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MallocLu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值