day13 装饰器 迭代器 生成器(总结)
原创
©著作权归作者所有:来自51CTO博客作者一个土豆芽的原创作品,请联系作者获取转载授权,否则将追究法律责任
#####################################################
########## 1.0__装饰器----总结 #############
#####################################################
但是原理一样的,就是函数嵌套 + 闭包函数 +函数对象组成
首先说一下:无参装饰器 函数添加统计其执行时间的功能
######################### 1.0无参装饰器的实现 ########################
print("welcome to the index page")
print("run time is %s "%(stop-start))
print("welcome to the index page")
def wrapper(func):#通过参数接收外部的值
print("run time is %s " % (stop - start))
# 但是这种方法:违反了不能修改被装饰对象调用方式的原则所以需要换一种函数传参方式
print("welcome to the index page")
print('Welcome to the home page',name)
def wrapper(*args,**kwargs):#通过参数接收外部的值
print("run time is %s " % (stop - start))
# 这样我们便可以在不修改被装饰函数源代码和调用方式的前提下为其加上统计时间的功能,
# 只不过需要事先执行一次timer将被装饰的函数传入,
# 返回一个闭包函数wrapper重新赋值给变量名 /函数名index,如下
# 接下来是语法糖:Python提供了专门的装饰器语法来取代index=timer(index)的形式,
需要在被装饰对象的正上方单独一行添加@timer,当解释器解释到@timer时就会调用timer函数,
且把它正下方的函数名当做实参传入,然后将返回的结果重新赋值给原函数名
def wrapper(*args,**kwargs):#通过参数接收外部的值
print("run time is %s " % (stop - start))
@timer #index = timer(index)
print("welcome to the index page")
@timer #home = timer(home)
print('Welcome to the home page',name)
########################## 2.0 有参装饰器的实现 ######################
从无参装饰器的实现原理后,我们可以再实现一个用来为被装饰对象
def wrapper(*args,**kwargs):
# 而函数deco与wrapper的参数都有其特定的功能,不能用来接受其他类别的参数,
# 可以在deco的外部再包一层函数auth,用来专门接受额外的参数,这样便保证了在auth函数内无论多少层都可以引用到
# 另一方面,也是由于语法糖 的原因 @deco(index) 只能放一个参数所以我们需要在
def wrapper(*args,**kwargs):
def wrapper(*args,**kwargs):
# 先调用auth(driver='file'),得到@deco,deco是一个闭包函数,
# 包含了对外部作用域名字driver的引用,@deco的语法意义与无参装饰器一样
# 可以使用help(函数名)来查看函数的文档注释,本质就是查看函数的doc属性,
def wrapper(*args,**kwargs):#通过参数接收外部的值
print("run time is %s " % (stop - start))
print('Welcome to the home page',name)
Help on function wrapper in module __main__:
在被装饰之后home=wrapper,查看home.name也可以发现home的函数名确实是wrapper,
所以想要保留原函数的文档和函数名属性,需要修正装饰器!!!!!
def wrapper(*args,**kwargs):#通过参数接收外部的值
print("run time is %s " % (stop - start))
wrapper.__doc__ = func.__doc__
wrapper.__name__ = func.__name__
print('Welcome to the home page',name)
Help on function home in module __main__:
python中存在functools模块下提供一个装饰器wraps专门用来帮我们实现这件事,
from functools import wraps
def wrapper(*args,**kwargs):
print('run time is %s' %(stop_time-start_time))
print('Welcome to the home page',name)
#####################################################
########## 2.0__装饰器----总结 #############
#####################################################
迭代器即用来迭代取值的工具,而迭代是重复反馈过程的活动,
其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次“迭代”,
goods=['mac','lenovo','acer','dell','sony']
while index < len(goods):
而且以每次重新赋值后的index值作为下一次循环中新的索引进行取值,
2.1可迭代对象("可以转换成迭代器的对象"):从语法形式-->>内置有__iter__方法对象都是可迭代对象
可迭代对象(iterable).__iter__(): 得到迭代器对象(如果不知到是不是迭代对象可以自己试)
其中可迭代对象有: 字符串、列表、元组、字典、集合、打开的文件
2.2迭代器对象:内置有__next__方法并且内置有__iter__方法的对象
迭代器对象.__next__():会得到迭代器的下一个值
迭代器对象.__iter__():会得到迭代器的本身,(调了跟没调一个样子)
#######举例1.0################
i = iter(s) #本质就是在调用s.__iter__(),返回s的迭代对象
r1=next(i) #本质是调用i.__next__()
# print(r4) # #抛出StopIteration的异常,代表 值已经取尽,无值可取,迭代结束
基于索引的迭代取值,所有迭代的状态都保存在了索引中,而基于迭代器实现迭代的方式不再需要索引,
所有迭代的状态就保存在迭代器中,然而这种处理方式优点与缺点并存:
1、为序列和非序列类型提供了一种统一的迭代取值方式。
2、惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,
同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,
如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。
2、只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行next方法直到值取尽,
否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,
如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值。
#####################################################
########## 3.0__生成器----总结 #############
#####################################################
若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象
def my_range(start,stop,step=1):
# print(g) #<generator object my_range at 0x00000259DA125EC8>
# 生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器
#输出结果: <method-wrapper '__iter__' of generator object at 0x00000259DA125EC8>
#输出结果: <method-wrapper '__next__' of generator object at 0x0000018321235EC8>
# 因而我们可以用next(生成器)触发生成器所对应函数的执行,
## 触发函数执行直到遇到yield则停止,将yield后的值返回,并在当前位置挂起函数
# 再次调用next(g),函数从上次暂停的位置继续执行,直到重新遇到yield...
# 再一次调用next(g),函数从上次暂停的位置继续执行,直到重新遇到yield...
# 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代
File "G:/2020老男孩全栈/练习/装饰器 迭代器 生成器.py", line 461, in <module>
# 既然生成器对象属于迭代器,那么必然可以使用for循环迭代,如下:
def my_range(start,stop,step=1):
obj=my_range(1,7,2) #1 3 5
print(next(obj)) #StopIteration
for i in my_range(1,7,2):
有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,
但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值
print('get the food: %s, and start to eat' %food)
#可以拿到函数的生成器对象持续为函数体send值,如下:
print(g) # 输出结果: <generator object eater at 0x000001DA4F7C5EC8>
next(g) # 需要事先”初始化”一次,让函数挂起在food=yield,等待调用g.send()方法为其传值
生成器对象必须事先被初始化一次,让函数挂起在food=yield的位置,
等待调用g.send()方法为函数体传值,g.send(None)等同于next(g)。
# !!!我们可以编写装饰器来完成为所有表达式形式yield对应生成器的初始化操作,如下:!!!
def wrapper(*args,**kwargs):
print('get the food: %s, and start to eat' %food)
# 表达式形式的yield也可以用于返回多次值,即变量名=yield 值的形式,如下:
# !!!! 变量名 = yield + 值 !!!!