今日内容回顾7.12
异常捕获
-
什么是异常
异常就是程序运行的过程中出现了错误导致整个程序直接结束!!!
也就是程序中出现的报错也称之为bug!!!
- 异常的结构
-
关键字line所在行,精确的提示你哪一行代码出现的问题
下方也会列出,出错的代码。
-
最后一行冒号的左侧,提示信息是错误的类型
-
最后一行冒号右侧,提示错误的具体原因
-
异常的类型
异常的类型有很多种,以下简单的列举几种。
NameError IndexError KeyError SyntaxError TypeError
-
异常的分类
-
语法异常
语法异常是指在编写代码过程中语法不全、语法格式不规范等导致的。
是我们在编写代码中不允许出现的,一旦出现立即改正。
-
逻辑异常
逻辑异常是指在编写代码过程中,可能会因为思想中的情况与现实中代码不一致
这种问题可以出现,出现后改正即可,问题不大!!!
-
异常捕获实参演练
-
异常处理方式
-
方式1
基本语法结构
try: name """可能会出错的代码(被try监控)""" except NameError as e: """except(关键字) NameError(错误类型) as e:(e就是具体错误的原因)""" name = 'jason' # 对应错误类型的解决措施
可以使用多个也可以使用单个,这种方式针对性很强。需要写入准确的错误类型
或者如下填写多个所猜测的不确定类型,但是一旦错误类型不匹配同样抛出异常。
try: name except NameError as e: name = 'jason' # 对应错误类型的解决措施 except 错误类型1 as e: # e就是具体错误的原因 对应错误类型1的解决措施 except 错误类型2 as e: # e就是具体错误的原因 对应错误类型2的解决措施 except 错误类型3 as e: # e就是具体错误的原因 对应错误类型3的解决措施 except 错误类型4 as e: # e就是具体错误的原因 对应错误类型4的解决措施
-
方式2
万能异常处理
# 示例1 try: 123+'hello' """万能异常处理方式1""" except Exception as e: """对应的解决措施""" # 示例2 try: d = {'name':'jason'} d['pwd'] """万能异常处理方式21""" except BaseException as e: """对应的解决措施"""
-
-
异常捕获的其他操作补充
-
else与finally
try: name ='jason' except Exception as e: print(1111)"""try监测的代码出现问题则会执行此代码""" else: print(222222) """try监测的代码没有出现异常则会执行else的子代码""" finally: print(333333) """try监测的代码无论是否出现异常都会执行finally的子代码"""
-
断言
断言语句是一种调试工具,用来测试某个断言条件,如果断言条件为True
则程序继续正常执行,如果是false则会抛出异常。
name = 'jason' # 通过一系列的手段获取来的数据 assert isinstance(name, list) # 断言数据属于什么类型 如果不对则直接报错 对则正常执行下面的代码 print('针对name数据使用列表相关的操作')
-
主动抛出异常
关键字(raise)
name = input("username>>>:").strip() if name == 'jason': """条件成立后主动抛出异常""" raise Exception('提示错误信息') """raise后面的异常类型不写,默认抛出当前错误类型 如果有写错误类型则抛出当前所写类型,异常类型后面的提示代码 如果有写则返回该提示信息如果没有则没有 """ else print('判断不成立后执行的结果') """ 异常捕获能尽量少用就尽量少用 被try监测的代码能少就少,节省内存资源消耗!!! """
-
异常捕获练习
-
使用while+异常捕获实现for循环功能
list1 = [1,2,3,4,5,6] res = list1.__iter__() while True: try: print(res.__next__()) except Exception: break
-
实际项目错误演示
user_data = { '1': {'name': 'jason', 'pwd': '123', 'access': ['1', '2', '3']}, '2': {'name': 'kevin', 'pwd': '321', 'access': ['1', '2']}, '3': {'name': 'oscar', 'pwd': '222', 'access': ['1']}} is_login = { 'is_login': False, 'access_list': [] } def login_auth(func_id): def outer(func): def inner(*args, **kwargs): if is_login.get('is_login'): access = is_login.get('access') if func_id in access: res = func(*args, **kwargs) return res else: print('你当前没有编号为%s的函数执行权' % func_id) else: user_id = input('请输入用户编号>>>').strip() if user_id in user_data: username = input('请输入用户名>>>').strip() pwd = input('请输入密码>>>').strip() real_dict = user_data.get(user_id) if username == real_dict.get('name') and pwd == real_dict.get('pwd'): access = real_dict.get('access') is_login['is_login'] = True is_login['access_list'] = access if func_id in access: res = func(*args, **kwargs) return res else: print('你没有当前功能编号为%s的函数执行权' % func_id) return inner return outer @login_auth('1') def func1(): print('from func1') func1() ''' 1.先看最后一行冒号右边的具体的报错信息 2.再看line所在的那行具体的定位信息 3.然后看line所在行下面的报错显示的错误代码 4.注意力就关注在出现这个变量的代码身上即可 '''
生成器对象
-
什么是生成器对象
生成器的本质就是迭代器对象
只不过迭代器是解释器给我们提供的,而生成器是我们直接定义的。
-
生成器对象的作用
生成器对象可以优化代码,是一种不依赖索引取值的通用方式
可以节省数据类型占用内存空间的问题。
-
生成器对象代码实现
函数+关键字yield的使用
""" 当函数体代码中有yield关键字 那么函数名第一次加括号调用不会执行函数体代码 而是由普通的函数变成了生成器对象 """ def index(): print('我是函数体代码1') yield '我是返回值1' print('我是函数体代码2') yield '我是返回值1' print(index()) # <generator object index at 0x0000021DE9F5CAC0> res = index() print(res) # <generator object index at 0x0000025F24A4CAC0> # 此时的res就是一个生成器对象也就是迭代器对象 res.__next__() # 我是函数体代码1 res.__next__() # 我是函数体代码2 """ yield可以在函数体代码中出现多次 每次调用__next__方法都会触发执行函数体代码 直到遇到yield代码停留在此处,等待下一次调用 """ print(res.__next__()) print(res.__next__()) # 我是函数体代码1 # 我是返回值1 # 我是函数体代码2 # 我是返回值1 """ yield后面如果有数据值 则会像return一样返回出去 如果有多个数据值逗号隔开 那么也会自动组织成元组返回 """
-
课堂练习
编写生成器实现内置函数range方法的功能
def my_range(x, y=0, z=1): z = abs(z) if y: x, y = y, x while y < x: yield y y += z for i in my_range(1,10,2): print(i) # 1、3、5、7、9
yield其他用法
-
yield与send结合用法
yield不单单向外面返回数据还可以接收数据
def index(name,food=None): print(f'{name}准备干午饭!!!') while True: food = yield print(f'{name}正在{food}') res = index('jason') res.__next__() # 传值给yield并自动调用__next__方法 res.send('吃生蚝') # jason正在吃生蚝 res.send('吃烤羊腰子') # jason正在吃烤羊腰子 res.send('做大宝剑') # jason正在做大宝剑 # 生成器res调用send方法可以向yield传值,并调用__next__方法
生成器表达式
-
什么是生成器表达式
可以简单的理解为使用for能够快速的构造一个生成器对象。
tuple1 = ( i for i in range(10) ) print(tuple1) # <generator object <genexpr> at 0x00000249C8ACCAC0> # 此时的tuple1就是一个生成器对象,可以多次调用__next__方法将其依次取出。 print(tuple1.__next__()) # 0 print(tuple1.__next__()) # 1 print(tuple1.__next__()) # 2 # 也可以使用类型转换将其转换为列表类型全部取出。 print(list(tuple1)) # [3, 4, 5, 6, 7, 8, 9] # 面试题 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) """ 第一次for循环 g = (add(n, i) for i in g) 第二次for循环 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] ps:掌握技巧即可 无需深究 纯粹为了考试而出 没有多少实际意义 嵌套不符合编程规范
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)