其他分享
首页 > 其他分享> > 异常捕获、生成器

异常捕获、生成器

作者:互联网

异常捕获

异常简介

1.如何理解异常?
	程序员在运行代码的时候,如果出现了异常会导致整个程序的结束,异常就是程序员口中的bug
2.异常结构
	2.1 关键字line所在的行:精准提示在代码的哪一行出错
	2.2 最后一行冒号左侧:是错误类型
	2.3 最后一行冒号右侧:是错误的具体原因(是改bug的关键)
    ps:处理异常的时候,常常从下往上查看异常提示
3.异常的类型
	常见的异常类型有NameError(名字错误)、IndexError(索引错误)、KeyError(键值错误)、SyntaxError(语法错误)、TypeError(类型错误)
4.异常的分类
	4.1 语法错误:是不允许出现的,编写代码时标红提示就应立刻修改
    4.2 逻辑错误: 是允许出现的,代码运行后报错就立刻修改

异常捕获简介

当代码不确定在未来什么时候会报错的情况下,我们可以使用异常捕获,它的使用相当于是提前预测可能出现的问题并提前给出处理的措施

异常捕获的代码实现

	1. 基本语法结构(针对性强)
    try:
        可能会出错的代码(被try监控)
    except 错误类型1 as e: # e就是具体的错误原因
        对应错误类型1的解决措施
	except 错误类型2 as e: # e就是具体的错误原因
		对应错误类型2的解决措施
	except 错误类型3 as e: # e就是具体的错误原因
		对应错误类型3的解决措施
	.....后面还可以写其他可能出现的错误类型,及解决措施
	2. 万能异常(笼统的处理方式)
    try:
        可能会出错的代码(被try监控)
    except Exception as e :
        解决措施

    try:
        可能会出错的代码(被try监控)
    except BaseException as e:
        解决措施
    ps:Exception与BaseException关系:BaseException 是 Exception 的父类

异常捕获的其他操作

	1. else与 finally
	try:
        可能会出错的代码(被try监控)
    except Exception as e:
        代码出错的执行代码
    else:
        try监测的代码没有出错的情况下正常运行结束 则会执行else子代码
    finally:
        try监测的代码无论有没有出错 最后都会执行finally子代码
	2. assert断言:用于判断的一个表达式,当表达式条件为false的时候回触发异常
    	eg:
		name = 'jason' # 通过一系列的手段获取来的数据
		assert isinstance(name,list) # 断言数据属于什么类型,如果不对则直接报错,如果正常就执行下面的代码
		print('针对name数据使用列表相关的操作')
	3. 主动抛出异常
		3.3.1 raise + 异常类型 + 异常描述
		3.3.2 raise + Exception +(异常描述)
         eg:
         name = input('请输入你的用户名>>>:').strip()
		if name == 'nana':
			# raise NameError('报错')
			raise Exception('报错')
        else:
			print('不报错')
ps:异常捕获能少用就少用,且被try监测的代码能尽量少就尽量少

异常捕获练习

1.for循环内部的本质
  需求:使用while+异常捕获实现for循环的功能
    l1 = [1,2,3,4,5,6,7,8,9]
    res = l1.__iter__()
    while True:
        try:
            print(res.__next__())
        except  Exception as e:
            break
2.处理异常步骤
	2.1 先看具体的报错信息(异常结构的最后一行)
	2.2 再看具体的定位信息(关键字line所在的行,由下往上看)
	2.3 尽量将错误缩小到某个具体的变量
	2.4 注意力就关注在出现这个变量的代码身上即可

生成器对象

生成器对象简介

1.生成器对象的本质其实就是迭代器对象,其区别在于迭代器对象是解释器提供给我们的,直接使用即可,而生成器则需要我们自己定义
2.学习生成器对象的目的:为了优化代码
3.  生成器对象的作用:与迭代器对象的作用一样,给我们提供了一种不依赖于索引取值的方式,并且可以节省数据类型的内存空间

生成器对象的代码实现:调用关键字yield的函数

  1. 当函数体代码中有yield关键字,函数名加括号进行调用,并不会执行函数体代码,而是将普通的函数变成了迭代器对象(生成器)
    def func():
        print("在第一个yield上面")
        yield
    func()  # 第一次调用没有打印操作
    print(func) # <function func at 0x000001DC621DB1E0>  还是函数
    print(func())  # <generator object func at 0x0000021E3082EEB8> 第一次调用之后变成生成器
   
  1. yield 可以在函数体代码中出现多次,每次调用调用__next__方法都会从上往下执行,直到遇到yield代码就停住
    def func():
        print("在第一个yield上面")
        yield
        print("在第二个yield上面")
        yield	
        print("在第三个yield上面")
        yield
        print("在第四个yield上面")
        yield
    res = func()
    res.__next__() # 在第一个yield上面
    res.__next__() # 在第二个yield上面
    res.__next__() # 在第三个yield上面
    res.__next__() # 在第四个yield上面
	
  1. 如果yield后面有返回值,则会像return一样返回出去,如果有多个数据值,并用逗号隔开,也会像return一样用元组的形式返回出去
    def func():
        print("在第一个yield上面")
        yield 1
        print("在第二个yield上面")
        yield 1,2,3
        print("在第三个yield上面")
        yield
        print("在第四个yield上面")
        yield
    res = func()
    print(res.__next__())  # 在第一个yield上面 1
    print(res.__next__())  # 在第二个yield上面 (1, 2, 3)
    res.__next__() # 在第三个yield上面
    res.__next__() # 在第四个yield上面	

生成器对象实操

编写一个生成器 实现range方法的功能

思路:range方法可以填写一个、两个、三个参数都可以实现,为了让代码好编写,先实现两个参数,再实现一个参数,最后实现三个参数的生成器
1.两个参数的生成器
def define_range(a,b):
    while a < b:
        yield a
        a += 1
# res = define_range(1,3)
# print(res.__next__())
# print(res.__next__())
# print(res.__next__()) 
ps:代码重复,考虑用for循环,并且foe循环自动调用__next__方法
for i in define_range(1,10):
    print(i)

2.一个参数的生成器
def define_range(a,b = None):
    if not b:
        b = a
        a = 0
    while a < b:
        yield a
        a += 1
for i in define_range(10):
    print(i)

3.三个参数的生成器
def define_range(a,b = None,c = 1):
    if not b:
        b = a
        a = 0
    while a < b:
        yield a
        a += c
for i in define_range(1,10,2):
    print(i)

yield其他用法

yield不仅可以返回值,也可以接收值

def func(name,hobby = None):
    print(f'欢迎{name}再次光临')
    hobby = yield
    print(f'你的爱好是{hobby}')
    yield
res = func('nana')
res.__next__()  # 欢迎nana再次光临
res.send('read')  # 你的爱好是read
ps:此时send()方法会传值并且自动调用__next__方法

生成器表达式

创建一个生成器对象有两种方式,一种是调用带yield关键字的函数,另一种就是生成器表达式,与列表生成式的语法格式相同,只需要将[]换成()

1.表达式:(操作代码 for 变量名 in 迭代器对象 if 条件)
	eg:
	s1 = (i+3 for i in [1,2,3] )
    print(s1)  # <generator object <genexpr> at 0x0000024BE354EEB8>
    for i in s1:
        print(i) # 4 5 6	
2.习题
def add(n, i):  
    return n + i
def test():  # 生成器
    for i in range(4):
        yield i
g = test()  # 激活生成器
for n in [1, 10]:
    g = (add(n, i) for i in g)  # 此时的g只是一个生成器(<generator object ···),还没有执行__next__()方法
    """
    第一次for循环
        g = (add(n, i) for i in g)
    第二次for循环
        g = (add(n, i) for i in (add(n, i) for i in g))
    """
print(n) # 10
print(g)
res = list(g) # 内部进行for循环,自动调用了__next__方法
# g = (add(10, i) for i in (add(10, i) for i in g))
print(res)  # [20, 21, 22, 23]

标签:__,res,捕获,生成器,yield,print,异常,代码
来源: https://www.cnblogs.com/luonacx/p/16471294.html