异常处理 生成器

异常处理前戏

异常处理就类似于诸葛亮神机妙算。程序员在程序运行之前已经知道了程序哪里可能会有问题,于是就提前做一些预防措施。
附上丞相美图:
image

1.异常
	异常就是代码运行报错 行业俗语叫bug
	代码运行中一旦遇到异常会直接结束整个程序的运行 我们在编写代码的过程中药尽可能避免
2.异常分类
	语法错误
    	不允许出现 一旦出现立刻改正 
	逻辑错误
    	允许出现的 因为它一眼发现不了 代码运行之后才可能会出现
3.异常结构
	错误位置
 	错误类型

如何看pycharm报错

def func(): # 调用次数过多报错
    func()

func() 
# 点击红色箭头指向的蓝色路径 可以跳转到错误的位置 
# 红色框内是python解释器为你提供的 报错原因
# 上面这么多蓝色路径 是由于你代码引发的python解释器内部的一些错误

image

异常常见类型

简单了解即可,不必全部记住:

SyntaxError # 语法错误
NameError # 命名错误
IndexError  #索引错误
KeyError  # 键错误 
IndentationError  # 缩进错误

异常处理语法结构

try...excpet

    try:
        待监测的代码(可能会出错的代码)
    except 错误类型:
        针对上述错误类型制定的方案

# 1.基本使用
try:
    name
except NameError:
    print('发现NameError')  # 发现NameError
# 2.查看错误信息
try:
    name
except NameError as massage:
    print(massage)  # name 'name' is not defined
    print('发现NameError')  # 发现NameError
# ps: except子句 可以在异常名称后面指定一个变量。 这个变量会绑定到一个异常实例并将参数存储在 instance.args中。

# 3.多个excpet连续使用  只会有一个excpet执行
userdata = [1, 2, 3, 4]
try:
    userdata[100]  # indexerror
    name  # nameerror
except NameError as massage:
    print(massage)
    print('发现NameError')
except IndexError as massage:
    print(massage)
    print('发现IndexError')

# 最终结果
# list index out of range
# 发现IndexError

image

万能异常 Exception/BaseException

    try:
        待监测的代码(可能会出错的代码)
    except Exception as e:  # e就是系统提示的错误信息
        针对各种常见的错误类型全部统一处理

# 1.基本使用
try:
    name
except Exception as massage:
    print(massage)  # name 'name' is not defined
    print('我是万能异常 我很牛逼')

try:
    name
except BaseException as massage:
    print(massage)  # name 'name' is not defined
    print('我是上面那家伙他爸爸 ')

Exception/BaseException区别

区别: BaseException 是 Exception 的父类,作为子类的Exception无法截获父类BaseException类型的错误

BaseException: 包含所有built-in exceptions
Exception: 不包含所有的built-in exceptions,只包含built-in, non-system-exiting exceptions,像SystemExit类型的exception就不包含在里面。

# Python所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里:
# https://docs.python.org/3/library/exceptions.html#exception-hierarchy

作者:https://www.cnblogs.com/-chenxs/p/11206678.html

try...except...else

# 在被try检测的代码没有异常时 else下的子代码执行 类似于for...else、while...else
try:
    print('miku')  # 没有异常
except BaseException:
    print('这里不执行')
else:
    print('hello')  # 没有异常时执行 有异常不执行

try..except..else..finally

# finally语句下的子代码 无论是否抛出异常 都会执行
try:
    name
except BaseException:
    print('有异常')
else:
    print('有异常时不执行')
finally:
    print('不报错会执行= =')
    print('报错也执行=。=')

异常处理练习

# 使用while循环+异常处理+迭代器对象 完成for循环迭代取值的功能
l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
# 1.先将列表调用__iter__转变成迭代器对象
iter_l1 = l1.__iter__()
# 2.while循环让迭代器对象反复执行__next__
while True:
    try:
        print(iter_l1.__next__())
    except StopIteration as e:
        break

断言 assert

image

# 1.断言--使用assert 类似于做出预言
name = 'alice'
assert isinstance(name, int)  # name是int类型 我说的!耶稣都拦不住
# 上面断言失败 会抛出异常 AssertionError

# 2.断言成功
name = 'alice'
assert isinstance(name, str)
print('hello')  # 程序继续运行 什么也没发生

主动抛出异常 raise

raise 语句支持强制触发指定的异常
raise 唯一的参数就是要触发的异常。这个参数必须是异常实例或异常类(派生自 Exception 类)
# 1.例子
name = '星期六上班'
if name == '星期六上班':
    raise Exception('老子不干了')  # 触发Exception异常
else:
    print('无事发生')

image

异常处理何时使用

1.异常处理能尽量少用就少用
2.被try监测的代码能尽量少就尽量少
3.当代码中可能会出现一些无法控制的情况报错才应该考虑使用
	eg: 使用手机访问网络软件 断网
      编写网络爬虫程序请求数据 断网

更多推荐阅读:https://segmentfault.com/a/1190000007736783

生成器

概念

1.本质
	还是内置有__iter__和__next__的迭代器对象
2.区别
	迭代器对象是解释器自动提供的
    	数据类型\文件对象>>>:迭代器对象
	生成器对象是程序员编写出来的
    	代码、关键字>>>:迭代器对象(生成器)

创建生成器 yield关键字

def func():   # 一个函数
    print('hello')

def gen_obj():
    print('hello')
    yield   # 在函数中添加yield关键字

res = gen_obj()  # 调用函数 不会执行函数体代码 而是会产生生成器对象
print(type(res))  # <class 'generator'>

yield返回值

def gen_obj():
    print('hello')
    yield 111, 222, 333
    print('tell')
    yield 111, 222, 333
    print('me')
    yield 111, 222, 333

print(type(gen_obj))  # <class 'function'>
res = gen_obj()  # 调用gen_obj 变成一个生成器对象
print(type(res))  # <class 'generator'>
r1 = res.__next__()  # 运行到第一个yield停止 r1接受yield的返回值  # hello
print(r1)  # (111, 222, 333)
r2 = res.__next__()  # 运行到第二个yield停止 r1接受yield的返回值
print(r2)
r3 = res.__next__()
res.__next__()  # 报错 # StopIteration

用yield传值(了解)

def eat(name, food=None):
    print(f'{name}准备用餐')
    while True:
        food = yield
        print(f'{name}正在吃{food}')

res = eat('alice')  # 产生生成器
res.__next__()  # alice准备用餐
res.__next__()  # alice正在吃None
res.__next__()  # alice正在吃None

send

def eat(name, food=None):
    print(f'{name}准备用餐')
    while True:
        food = yield
        print(f'{name}正在吃{food}')


res = eat('alice')  # 产生生成器
res.send(None)  # TypeError: can't send non-None value to a just-started generator
res.send('汉堡')  # 1.将括号内的数据传给yield前面的变量名 2.再自动调用__next__
res.send('包子')
res.send('面条')

# 总结
# 在使用send方法前 必须下列二者选其一
res.__next__()
res.send(None)

生成式表达式

# 是创造生成器的简便写法!
l1 = (i ** 2 for i in range(100))  # 生成器对象
print(l1)  # <generator object <genexpr> at 0x000001DFC07F7E40>
for i in l1:
    print(i)

生成器面试题(了解)

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]
'''不用深入研究 大致知道起始数即可'''

练习题

生成器

# 1.
提示:
1、同一个生成器中的数据只能取一次,取完就没有了
2、生成器的特点惰性运算:不找生成器取值,它就根本不工作
def func():
    for i in range(4):
        yield i

g = func()

g1 = (i for i in g)
g2 = (i for i in g1)

print(list(g1))  # [0,1,2,3]
print(list(g2))  # []
如果将print(list(g1))注释掉打印出的结果是什么?

# 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)
# for循环n=10时,相当于g = (add(n, i) for i in (add(n, i) for i in g))

print(list(g))  # 现在生成器才运行

# 向最内层的g要值 # g=test() 要出来了啥 要出来了0,1,2,3 
# 然后此时n=10 # add(10,0) add(10,1) add(10,2) add(10,3) 所以[10,11,12,13]
# 相当于 (add(n, i) for i in [10,11,12,13])  # 是不是一下变简单了
# 结果是 [20,21,22,23]

# 3.进阶 (cpu烧了)
def add(n,i):
    return n+i
 
def test():
    for i in range(4):
        yield i
 
g=test()
for n in [1,10,5]:
    g=(add(n,i) for i in g)
 
print(list(g))  # [15,16,17,18]

image

感谢作者!!https://blog.csdn.net/weixin_64471900/article/details/124988686

异常处理

# 1.编写程序,在指定文件路径读方式打开指定文件名,要求如果文件不存在提示异常错误并且创建新的同名文件。
user_input = input('请输入文件名:').strip()
try:
    with open(f'{user_input}.txt', 'r', encoding='utf8') as f:
        print(f.read())
except FileNotFoundError:
    with open(f'{user_input}.txt', 'w', encoding='utf8') as f:
        pass

生成器模拟range方法

def my_range(start_num, end_num=None, step=1):
    # 判断end_num是否有值 没有值说明用户只给了一个值 起始数字应该是0 终止位置应该是传的值
    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,10):
    print(i)

作者:https://blog.csdn.net/AQIANKE/article/details/126269996

posted @ 2022-10-17 16:25  passion2021  阅读(78)  评论(0编辑  收藏  举报