手撕Python之生成器、装饰器、异常
凯子坚持 c 2024-09-10 14:05:02 阅读 51
1.生成器
生成器的定义方式:在函数中使用yield
yield值:将值返回到调用处
我们需要使用next()进行获取yield的返回值
yield的使用以及生成器函数的返回的接收next()
<code>def test():
yield 1,2,3
t=test()
print(t)
#<generator object test at 0x01B77A48>
#生成器对象的意思
#我们在函数中使用这个yield关键字,那么这个函数就是一个生成器函数
#t存放的是生成器对象的信息
#yield的作用类似于return 将值返回到调用的地方
#我们如何获取这个1呢?
#next(生成器对象)
print(next(t))
#(1, 2, 3)
#yied返回的内容我们需要通过next()进行一个获取的操作
有yiled的函数被称为生成器函数
对于性质一来说的话,yield会将后面的数据进行返回,返回到调用处
对于性质二的话,我们运行完yield之后,这个函数的运行位置就会被记录下来了
然后我们在交互模式再次进行这个next()的使用,进行返回值的获取那么就会从上次函数中结束的位置进行开始寻找数据然后进行返回的操作
然后后面如果没有yield的话,有个print('abc')
那么这个函数会将abc进行返回的,但是最终会进行报错的
就像下图所示
从下面的图片我们可以看的出什么呢?
<code>def test():
yield 1,2,3
print('abc')
yield 'a'
t=test()
print(t)
print(next(t))
#(1, 2, 3)
print(next(t))
'''
abc
a
'''
我们在编辑模式第一次调用next()的时候打印出的返回值是1 2 3
我们在函数中又添加了一个yield关键字
然后我们在交互模式再次进行next的调用
这次的返回值是abc a
我们在调用next()的时候,这个我们会回到上一次yield结束的后面的一个位置
然后从那里开始寻找关键字yield进行数据的返回的操作
next()的作用就是获取yield后面的内容的
我们每次调用的时候就会回到上次yield结束的位置,从那个位置开始
yield和return的区别就是return会直接将函数进行结束,但是yield会保留此次的位置,下次调用的时候就从这个位置开始进行
yield只会中断,但是不会进行结束的操作
def testa():
for i in range(1,10):
yield i
t1=testa()
#获取yield返回值的方式:next()
print(next(t1))
#每次获取一个值,有多少个值就获取多少次
print(next(t1))
print(next(t1))
print(next(t1))
print(next(t1))
print(next(t1))
print(next(t1))
'''
1
2
3
4
5
6
7
'''
#如果我们超出了了的话就是会报错了
#因为最后一个yield后面没有数据了
t2=testa()
#获取yield返回值的方法二
for n in t2:
print(n)
#我们通过for循环能够一次性拿完
#我们通过next()的时候我们需要的时候就可以进行调用,想拿几个就拿几个
print(next(t1))
#8
#我们需要用的时候就进行调用一下,不用就放着
对于获取yield我们有两种方法的,第一种就是进行Next函数的调用
第二种就是利用for循环,直接将对象当做条件进行循环,将这个函数中所有的yield后面的值进行返回
我们对于第一种的话,想什么时候用就什么时候用,随时能够进行调用的操作
2.装饰器
装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象
装饰器的定义:
1.嵌套函数
2.外函数返回内函数名
3.外函数中定义一个形参,形参用来接受被装饰的函数名信息
4.要添加的额外功能,写在内函数中
调用函数:函数名()
使用装饰器:@装饰器名(外部函数名)
'''
#定义装饰器
def funa(name):
def funb():
print('---开始执行函数---')
#在这个中间执行被装饰的函数
name()#这个形参是用来接受这个被装饰的函数名的信息
'''
name=testc
name()=testc()
'''
print('---函数执行完毕---')
return funb
#被装饰的函数
@funa
def testc():
print('执行testc函数')
testc()
'''
---开始执行函数---
执行testc函数
---函数执行完毕---
'''
@funa
def testd():
print('执行testd函数')
testd()
'''
---开始执行函数---
执行testd函数
---函数执行完毕--
'''
我们先进行装饰器的定义操作
1.嵌套函数
2.外函数返回内函数名
3.外函数中定义一个形参,形参用来接受被装饰的函数名信息
4.要添加的额外功能,写在内函数中
5.在内部函数中调用被装饰的函数,即外函数的函数名
我们的外函数有个形参name就是用来接受被装饰函数的函数名信息的
方便我们在内函数中进行调用
我们在被装饰的函数的定义上面加上 @外部函数名
那么就说明我们这个函数就已经被装饰好了
那么我们对testc进行调用的操作,那么就会运行我们之前在内部函数中做的装饰代码
总结:我们先会执行这个 @funa
@后面跟的是一个装饰器函数
然后就直接将这个testc的内容给到了name
给到name 之后我们就往后面走
执行内部函数,这个name=装饰的函数的函数名
我们先运行到@funa
然后就运行到def testc()
然后就def funa(name)
然后就运行到def funb()
运行到这个内部函数的时候
我们会直接返回这个funb()返回到被装饰的函数
就是返回到testc这里
那么到这里的话装饰就完成了
然后就直接跳到了testc()的带调用处
然后进行testc的调用的时候
我们就会直接调用装饰器内部函数
我们跳到testc()的地方的时候我们直接进行装饰器的内部函数的调用操作了
对于函数装饰的代码我们写在内部函数中
外部函数一定要定义形参,接受被装饰函数的函数名
不然我们在内部函数中无法进行被装饰函数的调用
那么装饰器的作用:在不改变原函数的情况下对函数进行一系列的装饰操作
就是一个外包操作的升级版本
def log(u):
def aaa(name,pwd):
d={'123456':{'pwd':'1234'},
'1234567':{'pwd':'12345'}
}
if name in d:
if pwd==d[name]['pwd']:
print("登录成功")
#调用被装饰的函数
u(name,pwd)#外部参数的形参是u
else:
print("密码错误")
else:
print("用户不存在")
return aaa
#取款
@log
def get_money(name,pwd):
print(f"取款1000")
#查询
def set_money(name,pwd):
print(f"存款1000")
get_money('1256','1234')
#通过装饰器我们能减少代码冗余的效果
不改变函数代码的情况下,对函数增加一系列的操作
3.异常
异常的概念
异常是指程序在运行过程中发生的错误或者不正常的情况。当Python检测到一个错误时,解释器就无法继续执行了,反而出现一些错误的提示。
根据报错信息我们能找到报错的地方
常见的异常
对异常的预防(try、except、Exception、raise、assert)
当我们遇到异常的时候程序会终止执行,可能还会导致软件崩溃,遇到异常的解决方法:
预防:添加容错代码(代码过多代码冗余)
解决:添加捕获异常部分(try、expect)
<code>num=input("请输入一个整数")
#异常解决方案一:添加容错代码
if num.isdigit():#判断字符串是否都是数字
num=int(num)
else:
print('输入的不是整数')
#异常解决方案二:捕获异常
try:
#可能会报错的语句
num=int(num)
except ValueError:#except异常类型---捕获对应的异常类型
#捕获到异常,处理的语句
print(f"输入{num}不是整型")
#报错的默认信息
except ValueError as v:#接受捕获的异常的报错信息
print(v)
else:
print("没有报错")
finally:
print("异常处理完毕")
#invalid literal for int() with base 10: '1.5'
print(1234)
#用except捕获到异常之后我们就在后面进行处理,提醒出现的异常
#多个expect的关系是或的关系,他们只会执行一个的
except异常类型:
对用户进行提醒的代码
如果我们不知道对应的异常类型的话
我们就写Exception ---万能异常
能接收所有的错误信息
能代替所有异常类型
如果我们看默认报错的话,我们就这么写
except Exception as a:
print(f"错误{a}")
这后面字母a,你想起什么字母就写什么字母
这个存储的是错误信息
finally 的话,不管有没有异常,都会执行下面的代码的
except和else关系是或,只能执行一个
try后面必须有一个except
finally不管是否发生异常,始终都会执行
raise会主动抛出异常
函数在出现异常的时候会将异常返回至函数调用处,在调用处就能进行处理操作
raise 异常类型(异常描述信息)---抛出异常
在后面加上异常提示信息
raise的用法:
<code>def test():
tel=input("请输入手机号码")
if not(tel.isdigit() and len(tel)==11):#号码写错的情况下就会进行下面的代码
#将错误信息抛出
raise ValueError("请输入正确的11位手机号码")
try:
test()
except Exception as e:
print(e)
assert语句的格式:
assert测试条件,错误信息
断言语句是一种调试工具,用来测试某个断言条件,如果断言条件为真,则程序将继续正常执行;如果条件为假,则会引发AssertionError异常并显示相关错误信息
try:
n=input("请输入数字")
assert n.isdigit(),'只能输入数字'
#断言异常的话就会提示后面的错误信息的
except AssertionError as a:
print(a)
print('6')
assert n.isdigit(),'只能输入数字'
assert 判断条件 ,‘报错信息’
4.模块
模块的简介
Python中的模块,指的就是一个py文件。对于一个py文件,可以只用import来导入其中的代码
模块的使用:import 模块名
import keyword---查看关键字
import random---电脑产生随机值
模块的分类
内置模块:这类模块是Python自带的,可以直接导入使用。
第三方模块:也就是别人写好的一些模块,你要安装之后才可以用(先下载再导入使用 )。
3.自定义模块:自己在项目中定义的一些模块,注意自定义模块的时候命名要遵循标识符规定和变量的命名规范,并且不要与内置模块起冲突,否则将导致模块功能无法使用。
不能和内置模块冲突了
我们在同一文件夹中写一个py文件
然后在这个文件里面导入另一个文件
假设另外一个文件叫test.py
里面有个名字
我们在这个文件中写
import test
print(test.name)
我们需要先将test.py里面的代码运行进行保存
我们在别的文件才能进行调用
最好将这几个文件放到同一个目录之下
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。