一、有参装饰器

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 迭代器的优缺点

优点:

  1. 为序列与非序列类型提供了一种统一的迭代取值方式
  2. 惰性计算,迭代器本身是一个数据列,可以只在需要的时候去调用next取得下一个值,在同一时间内,迭代器只存在一个值。所以迭代器的容量是无线大的,但是对于其他的容器类型,如列表,通常不会一次性存放很多个值,受内存大小限制。

缺点:

  1. 除非用完整个迭代器,否则无法获取迭代器长度
  2. 只能取下一个值,不能控制他如何取值,如果要重新开始,就要重新定义一个迭代器对象

三、生成器

我们之前获得的迭代器都是通过可迭代对象获得的,那么如果自定义一个迭代器呢

在函数内一旦存在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 装饰器(下)+迭代器+生成器的更多相关文章

  1. Python装饰器、迭代器&生成器、re正则表达式、字符串格式化

    Python装饰器.迭代器&生成器.re正则表达式.字符串格式化 本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用 ...

  2. Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化

    本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解 ...

  3. 4 - 函数&装饰器 and 迭代器&生成器

    函数是什么 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的.程序里函数的定义是: 定义:将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 ...

  4. python 函数之装饰器,迭代器,生成器

    装饰器 了解一点:写代码要遵循开发封闭原则,虽然这个原则是面向对象开发,但也适用于函数式编程,简单的来说,就是已经实现的功能代码不允许被修改但 可以被扩展即: 封闭:已实现功能的代码块 开发:对扩张开 ...

  5. Python之装饰器、迭代器和生成器

    在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思 ...

  6. Python之函数(自定义函数,内置函数,装饰器,迭代器,生成器)

    Python之函数(自定义函数,内置函数,装饰器,迭代器,生成器) 1.初始函数 2.函数嵌套及作用域 3.装饰器 4.迭代器和生成器 6.内置函数 7.递归函数 8.匿名函数

  7. 简学Python第四章__装饰器、迭代器、列表生成式

    Python第四章__装饰器.迭代器 欢迎加入Linux_Python学习群  群号:478616847 目录: 列表生成式 生成器 迭代器 单层装饰器(无参) 多层装饰器(有参) 冒泡算法 代码开发 ...

  8. Day4-Python3基础-装饰器、迭代器

    今日内容: 1.高阶函数 2.嵌套函数 3.装饰器 4.生成器 5.迭代器 1.高阶函数 定义: a:把一个函数名当作实参传给函数 a:返回值包含函数名(不修改函数的调用方式) import time ...

  9. 循序渐进Python3(四) -- 装饰器、迭代器和生成器

    初识装饰器(decorator ) Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数. 使用 decorator 用Python提供的 @ 语法 ...

随机推荐

  1. Spark-stream,kafka结合

    先列参考文献: Spark Streaming + Kafka Integration Guide (Kafka broker version 0.10.0 or higher):http://spa ...

  2. <OPTEE>Trusted Application结构分析

    最近又开始和Trusted Zone打起了交道,需要把Linaro开发的开源安全系统optee os移植到实验室的老板子上.不过导师要求我先开发一个应用,在普通环境和安全环境分别有一个程序,称为hos ...

  3. 「雅礼集训 2017 Day4」洗衣服

    题目   点这里看题目. 分析   首先考虑只有洗衣机的情况.我们可以想到,当前洗衣任务结束越早的洗衣机应该被先用,因此可以用堆来动态维护.   再考虑有烘干机的情况.很显然,越晚洗完的衣服应该越早烘 ...

  4. 网页元素居中的n种方法

    导语:元素居中对齐在很多场景看上去很和谐很漂亮.除此之外,对于前端开发面试者的基础也是很好的一个考察点.下面跟着作者的思路,一起来看下吧. 场景分析 一个元素,它有可能有背景,那我要它的背景居中对齐 ...

  5. 使用 Kafka + Spark Streaming + Cassandra 构建数据实时处理引擎

    Apache Kafka 是一个可扩展,高性能,低延迟的平台,允许我们像消息系统一样读取和写入数据.我们可以很容易地在 Java 中使用 Kafka. Spark Streaming 是 Apache ...

  6. 消息队列——RabbitMQ的基本使用及高级特性

    文章目录 一.引言 二.基本使用 1. 简单示例 2. work queue和公平消费消息 3. 交换机 三.高级特性 1. 消息过期 2. 死信队列 3. 延迟队列 4. 优先级队列 5. 流量控制 ...

  7. Dubbo——服务调用过程

    文章目录 引言 服务的交互 服务降级 集群容错 服务调用 服务端接收请求 总结 引言 经过之前文章的铺垫,现在可以来分析服务的交互调用过程了. 服务的交互 服务降级 从名字上看我们不难理解MockCl ...

  8. 解决:Invalid character found in the request target.The valid characters are defined in RFC 7230 and RF

    背景 在将tomcat升级到7.0.81版后,发现系统的有些功能不能使用了,查询日志发现是有些地址直接被tomcat认为存在不合法字符,返回HTTP 400错误响应,错入信息如下: 原因分析 经了解, ...

  9. 8.eclipse 安装 lombook插件

    参考博客:https://www.liangzl.com/get-article-detail-129979.html

  10. disruptor架构四 多生产者多消费者执行

    1.首先介绍下那个时候使用RingBuffer,那个时候使用disruptor ringBuffer比较适合场景比较简单的业务,disruptor比较适合场景较为复杂的业务,很多复杂的结果必须使用di ...