Python异常:出了问题怎么办?快来用try-except-else-finally

异常(Exceptions)是什么

Python 使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让 Python 不知所措的错误时,它都会创建一个异常对象。如果你编写了处理该异常的代码,程序将继续运行;如果你未对异常进行处理,程序将停止,并显示一个 traceback ,其中包含有关异常的报告。

除零错误ZeroDivisionError: division by zero

1/0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-2-9e1622b385b6> in <module>
----> 1 1/0
ZeroDivisionError: division by zero

事实上,异常不仅能用来显示错误信息,它还是某个类的实例(这里是ZeroDivisionError)。程序员可以各种方式引发和捕获这些实例,从而采取措施修改程序。

命名错误NameError: name ‘ok’ is not defined

ok
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

<ipython-input-3-92a949fd4184> in <module>
----> 1 ok
NameError: name 'ok' is not defined

类型错误TypeError

2 + '2'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

<ipython-input-4-82150feed70c> in <module>
----> 1 2 + '2'
TypeError: unsupported operand type(s) for +: 'int' and 'str'

python标准异常

异常名称描述
BaseException所有异常的基类
SystemExit解释器请求退出
KeyboardInterrupt用户中断执行(通常是输入^C)
Exception常规错误的基类
StopIteration迭代器没有更多的值
GeneratorExit生成器(generator)发生异常来通知退出
StandardError所有的内建标准异常的基类
ArithmeticError所有数值计算错误的基类
FloatingPointError浮点计算错误
OverflowError数值运算超出最大限制
ZeroDivisionError除(或取模)零 (所有数据类型)
AssertionError断言语句失败
AttributeError对象没有这个属性
EOFError没有内建输入,到达EOF 标记 好像是读取异常
EnvironmentError操作系统错误的基类
IOError输入/输出操作失败
OSError操作系统错误
WindowsError系统调用失败
ImportError导入模块/对象失败
LookupError无效数据查询的基类
IndexError序列中没有此索引(index)
KeyError映射中没有这个键
MemoryError内存溢出错误(对于Python 解释器不是致命的)
NameError未声明/初始化对象 (没有属性)
UnboundLocalError访问未初始化的本地变量
ReferenceError弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError一般的运行时错误
NotImplementedError尚未实现的方法
SyntaxErrorPython 语法错误
IndentationError缩进错误
TabErrorTab 和空格混用
SystemError一般的解释器系统错误
TypeError对类型无效的操作
ValueError传入无效的参数
UnicodeErrorUnicode 相关的错误
UnicodeDecodeErrorUnicode 解码时的错误
UnicodeEncodeErrorUnicode 编码时错误
UnicodeTranslateErrorUnicode 转换时错误
Warning警告的基类
DeprecationWarning关于被弃用的特征的警告
FutureWarning关于构造将来语义会有改变的警告
OverflowWarning旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning关于特性将会被废弃的警告
RuntimeWarning可疑的运行时行为(runtime behavior)的警告
SyntaxWarning可疑的语法的警告
UserWarning用户代码生成的警告

处理异常(try…except…)

处理异常的目的

当你知道你的代码可能会产生某种异常, 但是你却不希望, 当这种异常出现的时候导致程序终止, 你想要让程序即使出现了异常也能跳过去继续向下运行, 这时候你就需要添加try/except 或try/finally语句来处理它。

假设创建了一个程序,让用户输入两个数,再将它们相除,如下所示:

x = int(input('Enter the first number:'))
y = int(input('Enter the second number:'))
print(x/y)
Enter the first number:1
Enter the second number:2
0.5

为捕获这种异常,并对错误进行处理,这里只输出一条对用户的错误信息,可以重写程序如下:

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 be zero!")
Enter the first number5
Enter the second number0
The second number can't be zero!
def f(a, b):
    if b == 0:
        return "您的输入有错误, 分母不能为0, 请重新输入!"
    return a/b

我们可能会自然的使用条件判断语句来完成异常处理的目标, 但这样编写出来的代码, 没有使用try/except的可读性那么高。

def f1(a, b):
    try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
        return a / b
    except: # 当try里面的代码有问题的时候, 则跳到except里面去运行
        return '您有输入错误, 分母不能为0'

可以通过指定错误类型的方法, 让try语句只捕捉指定异常类型

def f2(a, b, c):
    try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
        return a / (b+c)
    except TypeError as e: # 当try里面的代码有问题的时候, 则跳到except里面去运行
        print('您的错误信息是:', e)
f2(1,3,'a')
您的错误信息是: unsupported operand type(s) for +: 'int' and 'str'
f2(1,0,0)
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-9-3e105ee556ce> in <module>
----> 1 f2(1,0,0)
<ipython-input-7-adf24eadb550> in f2(a, b, c)
      1 def f2(a, b, c):
      2     try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
----> 3         return a / (b+c)
      4     except TypeError as e: # 当try里面的代码有问题的时候, 则跳到except里面去运行
      5         print('您的错误信息是:', e)

ZeroDivisionError: division by zero

这时可以设置多个except语句捕捉多个异常

错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。可以有多个except来捕获不同类型的错误:

def f3(a, b, c):
    try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
        return a / (b+c) 
    except TypeError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
        print('TypeError:', e)
    except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
        print('ZeroDivisionError:', e)
f3(4,0,0)
ZeroDivisionError: division by zero
f3(2, 0, '5')
TypeError: unsupported operand type(s) for +: 'int' and 'str'

我们也可以把多个错误类型同时放入到一个except语句中进行捕获

def f4(a, b, c, d):
    try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
        x = b + c
        y = d[3]
        z = a/b
        return x, y, z 
    except (TypeError,ZeroDivisionError, IndexError ) as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
        print('您的错误信息是:', e)
f4(1, 0, 2,[1, 2, 3, 4])
您的错误信息是: division by zero
f4(1, 3, 'a',[1, 2, 3, 4])
您的错误信息是: unsupported operand type(s) for +: 'int' and 'str'
f4(1, 3, 5,[1, 2])
您的错误信息是: list index out of range

finally和else的使用

当我们认为某些代码可能会出错时,就可以用try来运行这段代码,

如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。

try-except-else 代码块的工作原理:
Python会先尝试执行try代码块中的代码;只有可能引发异常的代码才有必要放到try语句中。有时,有一些代码只有在try代码块执行没问题时才需要执行,这些代码我们把它放到else代码块中。except代码块在try执行时引发了异常才会执行。

try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
    print( 10 / 2 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
    print('ZeroDivisionError:', e)
else:
    print('else里面的代码')
5.0
else里面的代码
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
    print( 10 / 0 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
    print('ZeroDivisionError:', e)
else:
    print('else里面的代码')
ZeroDivisionError: division by zero

finally子句

try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
    print( 10 / 2 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
    print('ZeroDivisionError:', e)
finally:
    print('finally里面的代码')
5.0
finally里面的代码
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
    print( 10 / 0 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
    print('ZeroDivisionError:', e)
finally:
    print('finally里面的代码')
ZeroDivisionError: division by zero
finally里面的代码

上述示例,不管try子句发生什么异常,都将执行finally子句。可用于在发生异常时执行清理工作,这个子句是与try子句配套的。

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

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-15-38d8b6ee80bd> in <module>
      1 try:
----> 2     1 / 0
      3 except NameError:
      4     print("Unknown variable")
      5 else:
ZeroDivisionError: division by zero
try:
    x = 1 / 1
except NameError:
    print("Unknown variable")
else:
    print("That went well!")
finally:
    print("Cleaning up.")
    del x
That went well!
Cleaning up.

捕获到异常时,如果不想吭气,可以用pass语句。

def readandprint(filename):
    """读取文件内容打印出来"""
    try:
        with open(filename) as f:
            contents = f.read()
    except FileNotFoundError:
        #print(filename+" 不存在.")
        pass
    else:
        print(contents)

readandprint("1s.txt")
with open("PrideandPrejudice.txt",encoding="UTF-8") as f:
    contents = f.read()
    words = contents.split()
    num_words = len(words) #总单词数
    print(num_words) 
    feq = contents.count("Mary") #统计 Mary 出现的次数.
    print(feq)
124706
39

参考文献:Python编程从入门到实践/(美)埃里克 马瑟斯(Eric Matthes)著;袁国忠译.–北京:人民邮电出版社,2016,7

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值