小白学python系列————【Day28】异常捕获及生成器对象

今日内容概要

  • 异常捕获
  • 异常捕获实参演练
  • 异常捕获练习
  • 生成器对象
  • yield其他用法
  • 生成器表达式(元组)

(一)异常捕获

1.如何理解异常:
程序在运行的过程中如果出现了异常会导致整个程序的结束
异常就是程序员口中的‘bug’

2.异常的结构:

Traceback (most recent call last):
 File "E:/pythonProject/Day21/02 练习.py", line 1, in <module>
   name
NameError: name 'name' is not defined

(1)关键字line所在行
精准提示哪一行代码出错。
line 1表示报错位置在代码第一行
(2)最后一行冒号左侧
代表代码错误类型
NameError表示名字报错
(3)最后一行冒号右侧
说明错误的具体原因
name ‘name’ is not defined表示未定义名字‘name’

3.异常的类型:
表格列举如下

错误的类型详情
NameError使用一个还未被赋予对象的变量
IndexError下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError试图访问字典里不存在的键
SyntaxErrorPython代码非法,代码不能编译
TypeError传入对象类型与要求的不符合
ValueError传入一个调用者不期望的值,即使值的类型是正确的

4.异常的分类:
(1)语法错误
不允许出现的,一旦出现立刻修改!!!eg:代码编写if判断后没有加冒号
(2)逻辑异常
可以允许的,如果出现了尽快修改即可

(二)异常捕获实参演练

1.什么时候才可能需要自己写代码处理异常?
当代码不确定什么时候会报错的情况下。
举个栗子:编写网络爬虫访问网址数据并处理,有可能会出现断网数据没有处理不了。

2.异常捕获的使用好处:
相当于提前预测可能出现的的问题并提前给出处理的措施。

3.异常捕获的代码实现
(1)基本语法结构

try:
   可能会出错的代码(try监控)
except 错误类型1 as e:      # e就是具体错误的原因
   对应错误类型1的解决措施
except 错误类型2 as e:      # e就是具体错误的原因
   对应错误类型2的解决措施
except 错误类型3 as e:      # e就是具体错误的原因
   对应错误类型3的解决措施
except 错误类型4 as e:      # e就是具体错误的原因
   对应错误类型4的解决措施

举个栗子:

try:
   name
except NameError as e:
   print(e)     # name 'name' is not defined

(2)万能异常

try:
   可能会出错的代码
except Exception as e:      # 万能异常方式1
   print(e)
except BaseException as e:  # 万能异常方式2
   print(e)

举个栗子:

try:
   123 + 'hello'
except Exception as e:
   print(e)              # unsupported operand type(s) for +: 'int' and 'str'
except BaseException as e:
   print(e)              # unsupported operand type(s) for +: 'int' and 'str'

4.异常捕获其它操作补充
(1)else与finally
try与else用法:try监测的代码没有出错的情况下正常运行结束 则会执行else子代码

try:
   name = 'jason'       # 这里为正确代码
except Exception as e:
   print('出错了')
else:
   print('没有出错')

try与finally用法:try监测的代码无论有没有出错 最后都会执行finally子代码

try:
   name    # 这里为错误代码
except Exception as e:
   print('出错了')
# else:
#     print('没有出错')
finally:
   print('不管你错没错,都要执行我')

(2)断言
断言数据属于什么类型,如果不对则直接报错,对了则正常执行下面的代码

name = 'jason'           # 通过一系列的手段获取来的数据
#assert isinstance(name,list)     # 猜错直接报错
assert isinstance(name,str)     # 猜对执行下面的代码
print('猜对了')   

(3)主动抛异常
想让报错就报错,全凭自愿

name = input('name>>>').strip()
if name == 'jason':
   raise Exception('反正就是错')
   # raise NameError('jason是错的')
else:
   print('剩下的都是对的')

5.异常处理使用准则
(1)异常捕获能尽量少用就尽量少用
(2)被try监测的代码能尽量少就尽量少

(三)异常捕获练习

1.for循环内部本质
需求:使用while+异常捕获实现for循环的功能

l1 = [11,22,33,44,55]
res = l1.__iter__()       # 将列表可迭代对象变成迭代器对象
while True:
   try:
       print(res.__next__())        # 可能会报错代码
   except Exception as e:
       break                        # 报错后直接结束循环

2.实际项目错误修改流程
(1)先看具体报错信息
(2)再看具体的定位信息(由下往上看)
(3)尽量将错误缩小到某个具体的变量
(4)注意力就关注出现这个变量的代码身上即可

(四)生成器对象

1.生成器对象的本质
生成器本质就是迭代器对象,唯一的区别就是迭代器对象是解释器提供给我们的,而生成器对象使我们自己定义出来的。

2.生成器对象的目的及作用
目的:为了优化代码
作用:一种不依赖于索引取值的通用方式;
可以节省数据类型的内存占用空间。

3.生成器对象代码实现
当函数体代码中有yield关键字,在没有调用函数之前,yield只是一个普通的函数

def index():
   print('jason')
   yield
print(index)     # <function index at 0x000001C7FA40D1E0>

当函数名第一次加括号调用后不会执行该函数体代码,而是将普通的函数变成了迭代器对象(生成器)

def index():
   print('jason')
   yield
res = index()
print(res)         # <generator object index at 0x000002BB0D9A2DB0>

yield可以在函数体代码中出现多次。
变成生成器对象之后调用__next__就会开始执行函数体代码,每次调用__next__方法都会从上往下执行直到遇到yield代码停留在此处

def index():
   print('jason')
   yield
   print('kevin')
   yield
   print('oscar')
   yield
res = index()
res.__next__()      
res.__next__()
res.__next__()


D:\Python36\python36.exe "E:/pythonProject/Day21/02 练习.py"
jason
kevin
oscar
Process finished with exit code 0

yield后面如果有数据值 则会像return一样返回出去
如果有多个数据值逗号隔开 那么也会自动组织成元组返回

def index():
   print('jason')
   yield 111,222,333
   print('kevin')
   yield 111,222
   print('oscar')
   yield 111
res = index()
print(res.__next__())
print(res.__next__())
print(res.__next__())



D:\Python36\python36.exe "E:/pythonProject/Day21/02 练习.py"
jason
(111, 222, 333)
kevin
(111, 222)
oscar
111

Process finished with exit code 0

4.课堂练习
需求:编写生成器 实现range方法的功能
(1)先考虑以两个参数的功能编写————range(1,10)

def num(start,end):
   while start < end:    # 判断开始值是否小于末尾值
       yield start       # 开始循环
       start += 1        # 循环每次自增1

for i in num(1,10):       # i循环取值
   print(i)              # 1 2 3 4 5 6 7 8 9

(2)然后考虑一个参数的情况————range(10)

def num(start,end=None):
   if not end:          # 将False条件变为True
       end = start      # start值绑定end
       start = 0        # start 绑定0
  while start < end:    # 判断开始值是否小于末尾值
       yield start       # 开始循环
      start += 1        # 循环每次自增1

for i in num(10):       # i循环取值
   print(i)          # 0 1 2 3 4 5 6 7 8 9 

(3)最后考虑三个参数的情况————range(1,10,2)

def num(start,end=None,step = 1):
   if step < 1:          
       step = 1
   if not end:          # 将False条件变为True
       end = start      # start值绑定end
       start = 0        # start 绑定0
   while start < end:    # 判断开始值是否小于末尾值
       yield start       # 开始循环
       start += step        # 循环每次自增1

for i in num(1,10,2):       # i循环取值
   print(i)    # 1 3 5 7 9

(五)yield其他用法

.send():传值并自动调用__next__方法

def index(name,food=None):
   print(f'{name}准备干午饭!!!')
   while True:
       food = yield
       print(f'{name}正在吃{food}')
res = index('jason')
res.__next__()
res.send('生蚝')  # 传值并自动调用__next__方法
res.send('韭菜')  # 传值并自动调用__next__方法

(六)生成器表达式(元组)

1.核心功能依旧是节省内存

2.语法结构

l1 = (i**2 for i in range(10) if i > 3)
print(l1)  # <generator object <genexpr> at 0x000001A793439C10>

3.面试例题(******)

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))         # 10+10
   """
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值