ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

异常捕获、生成器

2022-07-12 19:00:31  阅读:159  来源: 互联网

标签:__ res 捕获 生成器 yield print 异常 代码


异常捕获

异常简介

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有