day18 装饰器(下)+迭代器+生成器
一、有参装饰器
1 前提
上节课讲了无参装饰器的用法,模板如下:
def outter(func):#参数写死,为了给语法糖传值
def warpper(*args,**kwargs):#参数写死,为了给func传值
res = func(*args,**kwargs)
return res
return warpper
@outter
def index():
print("这是主页")
return 1
res = index()
print(res)
>>>这是主页
>>>1
从这段模板代码我们可以看出,装饰器的两个函数我们都无法为它增加新的参数传值
所以,当我们的装饰器需要跟多参数的时候,就只能通过闭包函数为他传值
2 如何使用有参装饰器
下面通过一个需求来表现有参装饰器的用途:
例:编写装饰器对多个函数添加认证功能,如果登录成功过,其他函数就不需要再次登录
分析需求:我们要编写认证功能的话只要添加个简单的有判断的装饰器即可,但是要判断之前是否成功过,我们就需要用到全局变量,如果登录成功把全局变量修改即可。所以我们在装饰器内部就要再判断一下,这个全局变量的值是什么,这里就会出现矛盾
我们要先判断全局变量,如果没有登录过,就修改他的值,这里违背了变量的先定义后引用的原则
所以基于这个矛盾,我们需要对装饰器传值,而在上面模板中我们已经知道,装饰器的函数我们都无法为他传值,因为各有用途都写死了。所以我们只能用第二种传值方式:闭包
is_login = True
def auth(login):
def outter(func):
def warpper(*args,**kwargs):
if login:
name = input("你的名字:")
pwd = input("你的密码:")
if name == "hz" and pwd == "123":
print("登录成功")
func(*args,**kwargs)
global is_login
is_login=False
else:
print("输入错误")
else:
func(*args,**kwargs)
return warpper
return outter
#语法糖的定义:被装饰函数 = @后面的东西(被装饰的函数)
#index = auth(is_login)(index)
#auth(is_login) == outter
#outter(index) ==warpper
@auth(is_login)
def index():
print("你好")
index()
@auth(is_login)
def home():
print("欢迎回家")
home()
3 有参装饰器模板
def 有参装饰器(x,y,z):
def outter(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
return outter
@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass
4 修正装饰器
我们的装饰器最终目的就是要把(原函数+装饰器)修改成和没有修改的函数一样(属性上)
但是,我们之前的学习装饰器还没有完成最终目的
@timer
def home(name):
'''
home page function
:param name: str
:return: None
'''
time.sleep(5)
print('Welcome to the home page',name)
print(help(home))
'''
打印结果:
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)
None
每个函数在定义出来后就有非常多的属性,名字,注释等等,我们如果一一修改就非常麻烦,这里可以用functools模块下提供的一个装饰器wraps专门用来帮我们实现这个:
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
二、迭代器
1 什么是迭代器
迭代:就是每一次重复都是基于上一次运行得到结果来进行循环,单纯的重复不是迭代
器:指工具
这里要区别两种类似的循环:
i = 0
while True:
i+=1
print(i)
while True:
print("i")
这两种都叫循环,但是第一种实现的就是迭代的过程,第二种就是单纯的循环
2 为什么要有迭代器
迭代器就是取值的工具,涉及到把多个值循环取出的类型
例:字符串,列表,字典,集合,元组,打开的文件
而上述6种数据类型,又分为可索引取值和不可索引取值
可索引取值:字符串,列表,元组
l = [1,2,3,4,5,6]
count = 0
while count<len(l):
print(l[count])
count+=1
明显从中可以看出,索引取值的局限性,于是就有了迭代器:不依赖索引取值的方式。
3 如何用迭代器
3.1 可迭代对象
可迭代对象是什么,可以做一个比喻
桌子上有三个东西,一个是活着的鸡,一个是烤箱,一个是烤鸡
活鸡:不能吃的东西,但是可以通过烤箱变成可以吃的烤鸡
烤箱:是一个把活鸡转换成烤鸡的工具
烤鸡:可以吃的东西
把上述比喻转化成程序思维
可迭代对象:不能进行迭代循环,但是可以通过工具转化成迭代器
“——iter——”方法:可以把可迭代对象转化成迭代器的工具
迭代器:可以进行迭代循环
这里就会有人有疑问,在编程中如何一下子判断这个对象是不是可迭代对象
我们可以通过iter方法测试一下,有这个内置方法他就是可迭代对象
s1=''
s1.__iter__()
l=[]
l.__iter__()
t=(1,)
t.__iter__()
d={'a':1}
d.__iter__()
set1={1,2,3}
set1.__iter__()
with open('a.txt',mode='w') as f:
f.__iter__()
pass
通过这个测试,我们发现我们需要测试的6种数据类型都是可迭代对象
那么,如何用可迭代对象进行迭代循环呢
第一步:把可迭代对象转化成迭代器
第二步:用next方法读取迭代器内的值
d={"A":1,"B":2}
d_i = d.__iter__()
while True:
print(d_i.__next__())
>>>A
>>>B
>>>抛出异常StopIteration
这里我们对抓取异常重新处理循环
d={"A":1,"B":2}
d_i = d.__iter__()
while True:
try:
print(d_i.__next__())
except StopIteration:
break
>>>A
>>>B
3.2 可迭代对象和迭代器对象详解
可迭代对象(可以转换成迭代器的对象):内置有iter方法的对象
可迭代对象.iter_():得到迭代器对象
迭代器对象:内置有iter方法和next方法的对象
迭代器对象._next _():得到迭代器的下一个值
迭代器对象._next _():得到迭代器对象本身,就是和没调用一样
可迭代对象:列表,字符串,字典,元组,集合,文件对象
迭代器对象:文件对象
4 for循环的工作原理
我们刚刚已经通过while循环解决了不可索引数据类型的迭代循环,这和for循环的工作原理基本一致
第一步:把我们需要循环的数据类型转换成迭代器对象
第二步:通过next方法拿到一个返回值,把这个值给i
第三步:循环步骤二,直到抛出StopIteration异常,for循环会捕捉异常并退出循环
l = [1,2,3]
for i in l :
print(i)
>>>1
>>>2
>>>3
5 迭代器的优缺点
优点:
- 为序列与非序列类型提供了一种统一的迭代取值方式
- 惰性计算,迭代器本身是一个数据列,可以只在需要的时候去调用next取得下一个值,在同一时间内,迭代器只存在一个值。所以迭代器的容量是无线大的,但是对于其他的容器类型,如列表,通常不会一次性存放很多个值,受内存大小限制。
缺点:
- 除非用完整个迭代器,否则无法获取迭代器长度
- 只能取下一个值,不能控制他如何取值,如果要重新开始,就要重新定义一个迭代器对象
三、生成器
我们之前获得的迭代器都是通过可迭代对象获得的,那么如果自定义一个迭代器呢
在函数内一旦存在yield关键字,调用函数并不会执行代码
会返回一个生成器对象,生成器就是自定义的迭代器
def func():
print('第一次')
yield 1
print('第二次')
g = func()#返回一个生成器对象
#g.__iter__()
#g.__next__()
#生成器就是迭代器
res = g.__next__()
print(res)
#通过next方法调用迭代器的下一个值,会执行第一个yield上面的代码,并将该yield的返回值返回
>>>第一次
>>>1
这里可以优化一下写法
iter(可迭代对象) == 可迭代对象.__iter__()
next(可迭代对象) == 可迭代对象.__next__()
模拟range,自定义一个迭代器
def my_range(start,stop,step):
while start<stop:
yield start #生成器取下一个值时函数从这下面开始运行
start += step
res = my_range(0,1000,7)
print(res.__next__())
print(res.__next__())
>>>0
>>>7
yield关键字不同于return,return是直接把函数结束,而yield是把函数在这里挂起,等待下一次调用,可以返回多个返回值
day18 装饰器(下)+迭代器+生成器的更多相关文章
- Python装饰器、迭代器&生成器、re正则表达式、字符串格式化
Python装饰器.迭代器&生成器.re正则表达式.字符串格式化 本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用 ...
- Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化
本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解 ...
- 4 - 函数&装饰器 and 迭代器&生成器
函数是什么 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的.程序里函数的定义是: 定义:将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 ...
- python 函数之装饰器,迭代器,生成器
装饰器 了解一点:写代码要遵循开发封闭原则,虽然这个原则是面向对象开发,但也适用于函数式编程,简单的来说,就是已经实现的功能代码不允许被修改但 可以被扩展即: 封闭:已实现功能的代码块 开发:对扩张开 ...
- Python之装饰器、迭代器和生成器
在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思 ...
- Python之函数(自定义函数,内置函数,装饰器,迭代器,生成器)
Python之函数(自定义函数,内置函数,装饰器,迭代器,生成器) 1.初始函数 2.函数嵌套及作用域 3.装饰器 4.迭代器和生成器 6.内置函数 7.递归函数 8.匿名函数
- 简学Python第四章__装饰器、迭代器、列表生成式
Python第四章__装饰器.迭代器 欢迎加入Linux_Python学习群 群号:478616847 目录: 列表生成式 生成器 迭代器 单层装饰器(无参) 多层装饰器(有参) 冒泡算法 代码开发 ...
- Day4-Python3基础-装饰器、迭代器
今日内容: 1.高阶函数 2.嵌套函数 3.装饰器 4.生成器 5.迭代器 1.高阶函数 定义: a:把一个函数名当作实参传给函数 a:返回值包含函数名(不修改函数的调用方式) import time ...
- 循序渐进Python3(四) -- 装饰器、迭代器和生成器
初识装饰器(decorator ) Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数. 使用 decorator 用Python提供的 @ 语法 ...
随机推荐
- 架构C02-商业模式与架构设计
商业模式与架构设计:A段架构与B段架构 <思考软件创新设计:A段架构师思考技术> A段架构师必须具备鲜活的创新思维,睿智的策略思考,犀利的洞察力和灵活的战术才能把握稍纵即逝的商机 ...
- 别让HR再质问我:我费劲招的人,你用缓存问废了,不能简单点?
概念 缓存穿透 在高并发下,查询一个不存在的值时,缓存不会被命中,导致大量请求直接落到数据库上,如活动系统里面查询一个不存在的活动. 缓存击穿 在高并发下,对一个特定的值进行查询,但是这个时候缓存正好 ...
- 【分区】使用 GPT 分区表分区并格式化 (非 FreeBSD 系统)
新购买的 Linux 云服务器,由于数据盘未做分区和格式化,无法使用. 注意: 数据盘中的数据在格式化后将全部被清空.请在格式化之前,确保数据盘中没有数据或已对重要数据进行备份.为避免服务发生异常,格 ...
- 从大厂DevOps工具链部署,看现代产品的生命周期管理
目录 1. 认识DevOps 1.1. DevOps工具链 1.2. CI 持续集成(Continuous Integration) 1.3. CD(持续交付 & 持续部署) 1.4. Agi ...
- [转] 允许root通过ssh远程登录
点击阅读原文 在Ubuntu中允许root远程访问 如果使用如xshell等远程工具首次通过root连接Ubuntu会提示拒绝访问,并不是密码不正确,而是Ubuntu默认禁止以root远程连接. 我们 ...
- Windows10 下安装和配置Redis
原文链接:https://blog.csdn.net/linghugoolge/article/details/86608897 一.下载地址https://github.com/MicrosoftA ...
- python中的importlib包
importlib.import_module(name, package=None) 导入一个模块.参数 name 指定了以绝对或相对导入方式导入什么模块 (比如要么像这样 pkg.mod 或者这样 ...
- 基于NACOS和JAVA反射机制动态更新JAVA静态常量非@Value注解
1.前言 项目中都会使用常量类文件, 这些值如果需要变动需要重新提交代码,或者基于@Value注解实现动态刷新, 如果常量太多也是很麻烦; 那么 能不能有更加简便的实现方式呢? 本文讲述的方式是, 一 ...
- 多语言工作者の十日冲刺<9/10>
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺--第九天(05.08) 作业正文 ...
- C#多线程编程(一)进程与线程
一. 进程 简单来说,进程是对资源的抽象,是资源的容器,在传统操作系统中,进程是资源分配的基本单位,而且是执行的基本单位,进程支持并发执行,因为每个进程有独立的数据,独立的堆栈空间.一个程序想要并发执 ...