当前位置:博客首页 > Python > 正文

第12课 Python3错误和异常处理

作者: Jarvan 分类: Python 发布时间: 2019-05-18 11:48 百度已收录

一、错误和异常的概念

1.1 错误

在程序上来讲错误主要有语法错误和逻辑错误。语法错误知识程序的结构上有错误,导致不能被解析器解析或编译器编译。这些错误必须在程序执行前纠正。逻辑错误可能是由于不完整或不合法的输入所致。

1.2 异常

异常就是因为程序出现了错误而在正常控制流以外才去的行为。这个行为又分为两个阶段:首先是引起异常发生的错误,然后是检测(和采取可能的控制措施)阶段。 第一个阶段是在发生了一个异常条件后发生的。只要检测到错误并且意识到异常条件,解析器就会引发一个异常,也叫触发异常或抛出异常。解析器通过它通知当前控制流有错误发生。python也允许程序员自己引发异常,无论是谁引发的,异常就是错误发生的信号。然后当前的流被打算,进入第二阶段。 对异常的处理,异常发生之后,可以调用很多不同的操作。可以是忽略错误或记录错误但不采取措施或采取补救措施后终止程序或者是减轻问题的影响后设法让程序继续执行。至于到底怎么做取决于程序员自己的。

二、python中的异常

2.1 几个异常的例子

  • NameError:尝试访问一个未声明的变量
  • ZeroDIvisionError:除数是0
  • SyntaxError:python解析器语法错误
  • IndexError:请求的索引操作范围
  • KeyError:请求一个不存在的字典关键词
  • IOError:输入、输出错误
  • AttributeError:访问一个不存在的属性

2.2 检测和处理异常

异常可以通过try语句来检测,任何在try语句块里面的代码都会被检测,检查有无异常发生。try语句有两种主要形式:try-except和try-finally。这两个句子是互斥的,也就是说你只能使用其中的一种。一个try语句亦可以对应一个或多个except语句,但只能对应一个finally语句,或是一个try-except-finally复合语句。

使用try-except语句

try:
    f = open('1.txt')
except IOError as e:
    print('open file error')

带有多个except的try语句

try:
    name = lilei
    n = int('hello')
    d = {}
    d.append('what')
except NameError as e:
    print('catch name error', e)
except TypeError as e:
    print('catch typeerror', e)
except AttributeError as e:
    print('catch attribute error', e)

捕获所有的异常

python中所有的异常都是继承自Exception这个类的,因此如果需要捕获所有的异常,那么直接捕获这个异常类即可,当然还有一种方法就是不写异常类也是代表捕获所有的异常。

try:
    name = lilei
    n = int('hello')
    d = {}
    d.append('what')
except Exception as e:
    print("error:", e)
try:
    name = lilei
    n = int('hello')
    d = {}
    d.append('what')
except:
    print("error")

一次性捕获多个异常

try:
    name = lilei
    n = int('hello')
    d = {}
    d.append('what')
except (NameError, TypeError, AttributeError) as e:
    print("error", e)

else语句

在异常中else语句表示如果没有异常发生则执行else语句里面的代码,需要放在except语句的后面。

try:
    name = lilei
    n = int('hello')
    d = {}
    d.append('what')
except (NameError, TypeError, AttributeError) as e:
    print "error", e
else:
    print("no exception error")

finally语句

finally语句表示无论异常是否发生,是否捕获,都会执行finally语句里面的代码。finally可以直接跟try单独使用,但是else语句是不行的。finally语句必须放在异常捕获语句的最后,而且只能出现一次。

# try-finally语句
try:
    name = hello
finally:
    print("就算发生异常我也会被执行")
# 结合except和else语句
try:
    num = int('hehe')
except ValueError as e:
    print("转换失败")
else:
    print("转换成功")
finally:
    print("无论是否转换成功我都会被执行")

三、自动触发异常

python提供了一种机制让程序员明确的触发异常,就是使用raise语句。

raise语句语法和用法

语法: raise[SomeException, [args, traceback]]] 第一个参数SomeException就是触发异常的名称,必须是类或实例。如果有其他参数,就必须提供SomeException。 第二个参数为可选参数,主要是将异常的参数传给异常,这个可以是一个单独的对象或一个对象的元组。当异常发生时,异常的参数总是作为一个元组传入。如果args是一个单独的对象就生成只有一个元素的元组。大多数情况下,单一的字符串用来指示错误的原因。如果传的是元组,通常组成的是一个错误字符串、一个错误编号、可能还有一个错误的地址,比如文件等等。 最后一项参数,traceback同样是可选的(基本上很少用到)。如果有的话,则是当异常触发时新生成的一个用于异常正常话的跟踪记录对象。当你想重新引发异常时,第三个参数很有用(可以用来区分先前和当前位置)。如果没有这个参数,就填None。 自动触发异常最常见的的用法为,直接raise一个异常,或者是后面再跟上异常说明。

用法示例:

# 直接触发一个异常
raise ValueError
# 触发一个异常,并填写自己的异常说明
raise TypeError("类型错误,请自行检查")

断言异常

断言是一句必须等价于布尔真的判断;此外,发生异常也意味着表达式为假。 断言语句语法: assert expression[, arguments]

说明: expression为断言表达式,如果表达式为真,则断言正确,如果为假则断言失败,引发断言异常AssertionError。 arguments参数为可选参数,主要是用于对异常原因进行补充说明,一般为一个字符串。 用法示例:

# 断言正确
assert 1==1
# 断言错误,引发断言异常
assert 1==0
list1 = [1,2,3,4]
assert list1[0] == 30, "第0个元素是30"

四、python内建异常

python内建异常
python内建异常

错误和异常处理

  1. 每种错误都有自己对应的异常类
  2. Exception能够捕获所有的错误
  3. try可以和except配对
  4. else语句是指没有异常发生的时候才会执行,必须放在except之后
  5. finally语句是指不管有没有异常发生,都会执行finally语句中的代码,放在最后
  6. 可以直接用try-finally语句
  7. 当try-finally语句中有错误发生的时候,程序执行完finally语句之后就会退出,不会继续往下执行
  8. 只有通过except语句捕获之后才会往下执行

作业

  1. 熟练使用python的异常处理
  2. 了解常见的异常原因以及解决办法
  3. 优化前面猜字游戏的程序,假如用户输入的不是数字而是别的东西要怎么处理才能让程序正常的执行下去而不至于中断?
  4. 自己动手写一个小爬虫(urllib包)尝试将所有的有可能发生错误的地方都用错误和异常进行处理

作业3解答:

import random
num1 = random.randint(1,20)
while True:
    num2 = input("请输入1~20之间随机一个数字,我会告诉你大了还是小了:")
    try:
        num3 = int(num2)
    except Exception:
        print("你输入的内容非整数,请继续输入!")
        continue
    if num3 == num1:
        print("你猜中了,恭喜你!")
        break
    elif num3 > num1:
        print("大了,请继续猜")
    else:
        print("小了,请继续猜")

作业4解答:

# -*- coding: utf-8 -*-

# from urllib import request
import urllib.request as requests


def download(url, ua=None, timeout=10, encoding='utf-8'):
    user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
                 "(KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36"
    if ua:
        user_agent = ua
    headers = {
        "User-Agent": user_agent
    }
    try:
        req = requests.Request(url, headers=headers)
        response = requests.urlopen(req, timeout=timeout)
    except (requests.URLError, requests.HTTPError):
        html = None
    else:
        html = response.read().decode(encoding)
    return html


def extract_title(source):
    try:
        start = source.find('<title>')
        end = source.find('</title>')
    except AttributeError:  # 传入的不是字符串
        return
    if start < 0 or end <= start:  # 没有找到
        return
    titile = source[start + 7: end]
    return titile


if __name__ == '__main__':  # 只有直接执行本模块的时候才会成立
    query = "http://www.sohu.com/a/238659707_123753"
    html = download(query)
    if html is None:
        print('get source error')
    else:
        title = extract_title(html)
        if title:
            print(title)
        else:
            print('get title error')
    print('Done.')

发表评论