异常处理、生成器

一、异常处理

  • 异常是指在语法正确的前提下,程序运行时报错就是异常。
  • 当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 尚未实现的方法

SyntaxError Python 语法错误

IndentationError 缩进错误

TabError Tab 和空格混用

SystemError 一般的解释器系统错误

TypeError 对类型无效的操作

ValueError 传入无效的参数

UnicodeError Unicode 相关的错误

UnicodeDecodeError Unicode 解码时的错误

UnicodeEncodeError Unicode 编码时错误

UnicodeTranslateError Unicode 转换时错误

Warning 警告的基类

DeprecationWarning 关于被弃用的特征的警告

FutureWarning 关于构造将来语义会有改变的警告

OverflowWarning 旧的关于自动提升为长整型(long)的警告

PendingDeprecationWarning 关于特性将会被废弃的警告

RuntimeWarning 可疑的运行时行为(runtime behavior)的警告

SyntaxWarning 可疑的语法的警告

UserWarning 用户代码生成的警告

异常处理语法结构:

1. 基本语法结构

try:

    待监测的代码(可能会出错的代码)

except  错误类型:    # 监测的代码是此处的错误类型,则会执行下方的代码

    针对上述错误类型制定的方案

监测的代码与错误类型一致,则会执行下方的子代码:

 

 监测的代码与错误类型不一致,则依然会报错:

 

 

2. 查看错误信息:

try:
    待监测的代码(可能会出错的代码)

except 错误类型 as e:  # e就是系统提示的错误信息
        
    针对上述错误类型制定的方案
print(e)

 

3. 针对不同的错误类型制定不同的解决方案

try:
    待监测的代码(可能会出错的代码)

except 错误类型1 as e:  # e就是系统提示的错误信息
       
   针对上述错误类型1制定的方案

except 错误类型2 as e:  # e就是系统提示的错误信息
        
   针对上述错误类型2制定的方案

except 错误类型3 as e:  # e就是系统提示的错误信息
        
   针对上述错误类型3制定的方案
     
           ...

一个except只能应对一种错误类型,如果错误类型很多的话我们有两种选择,一种是写很多个except把错误类型分开写全,第二种选择是在错误类型处写上Exception/BaseException

 

4. 万能异常 Exception  /BaseException

两个异常类型作用一样,都包含所有的错误类型,但是BaseException是Exception的父代码。

try:
   
待监测的代码(可能会出错的代码)
except Exception as e: # e就是系统提示的错误信息 针对各种常见的错误类型全部统一处理

 

5. 结合else使用

    咱们应该对else并不陌生,在if中,它的作用是当条件不满足时执行的实行;同样在try…except…中也是如此,即如果没有捕获到异常,那么就执行else中的子代码

try:
        
   待监测的代码(可能会出错的代码)
 
except Exception as e:  # e就是系统提示的错误信息
        
   针对各种常见的错误类型全部统一处理
 
else:
      
   try的子代码正常运行结束没有任何的报错后 再执行else子代码

 

6. 结合finally使用

    在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。

try:
       
    待监测的代码(可能会出错的代码)
    
except Exception as e:  # e就是系统提示的错误信息
        
    针对各种常见的错误类型全部统一处理
    
else:
        
     try的子代码正常运行结束没有任何的报错后,再执行else子代码
    
finally:
        
    无论try的子代码是否报错,最后都要执行finally子代码

 

异常处理补充

1. 断言 assert

name = 'jason'

assert isinstance(name, int)    # 报错
    
assert isinstance(name, str)    # 断言对了就正常往下,输出‘哈哈哈’
    
print('哈哈哈 ')
    

 

2. 主动报错 raise

    python中提供了一个 Exception 异常类

    在开发时,如果满足特定业务的需求时,希望抛出异常,可以

  1. 创建一个 Exception的对象
  2. 使用 raise关键字抛出异常对象

需求案例:

  1. 定义 input_password函数,提示用户输入密码
  2. 如果用户输入长度<8,抛出异常
  3. 如果用户输入长度>=8 返回输入的密码
def input_password():
    #1.提示用户输入密码
    result =input("请输入密码")
    #2.判断密码长度 >=8 ,返回用户输入的密码
    if len(result) >=8:
        return result
    #3.如果<8 主动抛出异常
    print("主动抛出异常!")
    #1>创建异常对象 -可以使用错误信息字符串作为参数
    ex =Exception("密码长度不够!")
    #2> 主动抛出异常
    raise ex
#提示用户输入密码
try:
    print(input_password())
except Exception as result:
    print(result)

 

异常处理实战应用

1. 异常处理能尽量少用就少用

2. 被try监测的代码能尽量少就尽量少

3. 当代码中可能会出现一些无法控制的情况报错才应该考虑使用

    eg: 使用手机访问网络软件,断网

          编写网络爬虫程序请求数据,断网

 

练习:

使用while循环+异常处理+迭代器对象,完成for循环迭代取值的功能

        l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]

l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
# 1.先将列表调用__iter__转换为可迭代对象
iter_l1 = l1.__iter__()
# 2. while循环让迭代器对象反复执行__next__操作
while True:
    try:
        print(iter_l1.__next__())
    except StopIteration as e:
        break

 

二、生成器(generator)

1. 本质:

  生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()__next__()方法了,只需要一个yiled关键字。

2. 区别:

迭代器对象是解释器自动提供的

    数据类型\文件对象>>>:迭代器对象

生成器对象是程序员编写出来的

    代码、关键字>>>:迭代器对象(生成器) 

3. 创建生成器的基本语法

    函数体代码中填写yield关键字

4. 创建一个generator

我们知道函数名加括号会执行函数体代码,当函数体代码中如果有yield关键字,那么函数名加括号并不会执行函数体代码,会生成一个生成器对象(迭代器对象)。

 

如何让函数体代码正常执行呢?需要使用加括号之后的结果调用__next__才会执行函数体代码。

 

 但如果第二次调用__next__又会报错

 

在函数执行过程中遇到 yield 时就返回并挂起函数,当再次调用 next 或者 for 循环取下一个元素(隐式调用next) 时,原本等待在 yield 处的函数就会继续往下走,直到再遇到一个 yield。

  注:yield还有点类似于return,可以返回返回值。

 

练习:

自定义生成器对标range功能(一个参数 两个参数 三个参数 迭代器对象)

for i in range(1, 10):

print(i)

1. 两个参数的

 

2. 一个参数的

 

3. 三个参数

 

补充:yield冷门用法:

当我们使用yield关键字的时候可以用变量名绑定yield关键字,然后就可以使用send方法传参,然后会再次运行到yield关键字处停止运行。

 

三、生成器表达式

列表生成式就是生成器的简化写法。

l1 = (i ** 2 for i in range(100))  # 生成器对象
print(l1)    # <generator object <genexpr> at 0x000001DFC07F7E40>

for i in l1:
    print(i)

 

面试题:(有难度)

大致知道流程即可
def add(n, i):
    return n + i
# 定义了一个add函数,作用求和

def test():  # 生成器
    for i in range(4):
        yield i
# 定义了一个生成器

g = test()  # 激活生成器
# 激活了生成器,这样就而已用for循环取值了
for n in [1, 10]:
    g = (add(n, i) for i in g)
    """
    第一次for循环
        这里就相当于给g重新绑定了一个生成器没有运行代码
        g = (add(n, i) for i in g)
    第二次for循环
        这里就相当于用到for循环去(add(n, i) for i in g)里面取值了,这个时候的n是10,生成器给的四个值是0、1、2、3,然后运行add就等于c选项
        g = (add(10, i) for i in (add(10, i) for i in g))
    """
res = list(g)
print(res)

# A. res=[10,11,12,13]
# B. res=[11,12,13,14]
# C. res=[20,21,22,23]
# D. res=[21,22,23,24]
'''答案:C'''

 

索引取值与迭代取值的差异

l1 = [11, 22, 33, 44, 55]

索引取值:

        可以任意位置任意次数取值

        不支持无序类型的数据取值

迭代取值:

        只能从前往后依次取值无法后退

        支持所有类型的数据取值(无序有序)

PS:两者的使用需要结合实际应用场景

posted @ 2022-10-17 17:13  莫~慌  阅读(280)  评论(0编辑  收藏  举报