异常捕获(迭代器)

异常(Bug)

  • 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行
  • 一般情况下,在Python无法正常处理程序时就会发生一个异常
  • 当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行
  • 程序在运行的过程中如果出现了异常会导致整个程序的结束

异常结构

image

  1. 关键字line所在行:精准提示哪一行代码出错
  2. 最后一行冒号左侧:错误类型
  3. 最后一行冒号右侧:错误具体原因(改bug关键)

异常类型

  • NameError:未声明/初始化对象 (没有属性)

  • IndexError:序列中没有此索引(index)

  • KeyError:映射中没有这个键

  • SyntaxError:Python 语法错误

  • TypeError:对类型无效的操作

异常分类

  1. 语法错误:不允许出现,一旦出现立刻修改
  2. 逻辑错误:允许出现,允许出错之后修改即可
  3. 写代码先自己测一遍,然后再提交

异常捕获实参演练

  • 当代码不确定什么时候会报错的情况下需要自己写代码处理异常

  • 异常捕获的使用相当于是提前预测可能出现的问题并提前给出处理的措施

  • 异常捕获代码实现:try/except语句

    • try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理,如果你不想在异常发生时结束你的程序,只需在try里捕获它
    1. 基本语法结构:
    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的解决措施
                 ...
    
    1. 万能异常(笼统的处理方式)
    try:
        可能会出错的代码
    except Exception as e: # 万能异常方式1
        print(e)
    except BaseException as e: # 万能异常方式2
        print(e)
    
  • 异常捕获其他操作补充

  1. else与finally

    • try....except...else语法
      • try监测的代码出错的情况下正常运行结束,不会执行else子代码
      • try监测的代码没有出错的情况下正常运行结束,则会执行else子代码
# try监测的代码出错的情况下正常运行结束,不会执行else子代码
try:
	name
except Exception as e:
	print('出错了')
else:
	print('try监测的代码没有出错的情况下正常运行结束,则会执行else子代码')

image

# try监测的代码没有出错的情况下正常运行结束,则会执行else子代码
try:
	name = 'jason'
except Exception as e:
	print('出错了')
else:
	print('try监测的代码没有出错的情况下正常运行结束,则会执行else子代码')

image

  • try…except…finall语法
  • try监测的代码无论有没有出错,最后都会执行finally子代码
# try监测的代码无论有没有出错,最后都会执行finally子代码
try:
	name
	# name = 'jason'
except Exception as e:
	print('出错了')
finally:
	print('try监测的代码无论有没有出错,最后都会执行finally子代码')

image

image

  1. 断言(assert)
    • 通过一系列的手段获取来的数据,断言数据属于什么类型,如果不对则直接报错,对则正常执行下面的代码
name = 'jason'
assert isinstance(name, list)  # 断言name属于list类型,如果不对则报错,对则执行后面的代码,感觉和if作用差不多
print('针对name数据使用列表相关的操作')
  1. 主动抛异常(raise)
    • raise语句主动触发异常
name = input('username>>>:').strip()
	if name == 'jason':
        # raise NameError('jason来了 快跑!!!')
        raise Exception('反正就是不能过')
     else:
        print('不是jason,那没事了')
  • try的工作原理:当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常

    1. 如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)
    2. 如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印默认的出错信息)
    3. 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句
  • 强调

    1. 异常捕获能尽量少用就尽量少用
    2. 被try检测的代码能尽量少就尽量少

异常捕获练习

  1. for循环内部本质
# 需求:使用while+异常捕获实现for循环的功能
l1 = [11, 22, 33, 44, 55, 66, 77, 88]
res = l1.__iter__()
while True:
	try:
		print(res.__next__())
	except Exception as e:
		break
  1. 错误演示
    1. 先看具体报错信息
    2. 再看具体定位信息(由下往上看)
    3. 尽量将错误缩小到某个具体的变量
    4. 注意力就关注在出现这个变量的代码身上即可

生成器

在 Python 中,使用了 yield 的函数被称为生成器。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

生成器对象

  • 本质:迭代器对象

    • 迭代器对象是编译器提供给我们的,现成的
    • 生成器对象是根据迭代器的原理,我们自己敲的,主要依赖__ iter__ 与__ next__方法 以及 yield关键字
  • 创建生成器对象:

    • 方式一:调用带yield关键字的函数
    • 方式二:生成器表达式
  • 作用:优化代码,提供一种不依赖于索引的取值方式,并在需要数据时一个一个取出,节省了占用空间

生成器函数

  • 当函数体代码中有yield关键字,那么函数名第一次加括号调用不会执行函数体代码,而是由普通的函数变成了迭代器对象(生成器)返回值
def index():
    print('你瞅啥')
    yield 

print(index)  # <function index at 0x000001F499F7A5E0>
res = index()
print(res)  # <generator object index at 0x0000021E18BACA50>
  • yield可以在函数体代码中出现多次,每次调用__ next__方法都会从上往下执行直到遇到yield代码停留在此处
def index():
    print('你瞅啥')
    yield 1
    print('瞅你咋地')
    yield 2
    print('爱瞅瞅')
    yield 3

print(index)
res = index()
print(res) 

res.__next__() # 你瞅啥
res.__next__() # 瞅你咋地
res.__next__() # 爱瞅瞅
  • yield后面如果有数据值,则会像return一样返回回去,如果有多个数据值逗号隔开,那么也会自动组织成元组返回
def index():
    print('你瞅啥')
    yield 1, 2, 3
    print('瞅你咋地')
    yield 2
    print('爱瞅瞅')
    yield 3

print(index)
res = index()
print(res) 
    
print(res.__next__()) # 你瞅啥 (1, 2, 3)
print(res.__next__()) # 瞅你咋地 2
print(res.__next__()) # 爱瞅瞅 3

生成器练习题

# 编写生成器,实现range方法的功能
# 1.先以两个参数的功能编写
def my_range(start_num, end_num):
    while start_num < end_num:
        yield start_num
        start_num += 1

for i in my_range(1, 10):
    print(i)

# 2.再考虑一个参数的情况
def my_range(start_num, end_num=None):
    if not end_num:
        end_num = start_num
        start_num = 0
    while start_num < end_num:
        yield start_num
        start_num += 1
for i in my_range(100):
    print(i)

# 3.最后考虑三个参数的情况
def my_range(start_num, end_num=None, step=1):
    if step < 1:
        step = 1
    if not end_num:
        end_num = start_num
        start_num = 0
    while start_num < end_num:
        yield start_num
        start_num += step
for i in my_range(1, 100, 2):
    print(i)
for i in my_range(1, 5):
    print(i)
for i in my_range(10):
    print(i)

yield其他用法

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__方法
res.send('钵钵鸡')  # 传值并自动调用__next__方法

生成器表达式

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


# 面试题(掌握技巧)
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]
 posted on 2022-07-12 17:39  念白SAMA  阅读(50)  评论(0)    收藏  举报