装饰器,迭代器,生成器
一、装饰器
无参装饰器的实现
如果想为下述函数添加统计其执行时间的功能
import time
def index():
time.sleep(3)
print('Welcome to the index page’)
return 200
index() #函数执行
闭包函数的方案:
import time
def index(): # index = 被装饰对象index函数的内存地址
time.sleep(1)
print('from index')
def outter(func): # func = 被装饰对象index函数的内存地址
def wrapper():
start = time.time()
func() # 被装饰对象index函数的内存地址()
stop = time.time()
print('run time is %s' %(stop - start))
return wrapper # 千万别加括号
index = outter(index) # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
print(index)
index()
无参装饰器的方案,将wrapper伪装成被装饰的函数,那么应该装的尽可能像一些:
import time
def index(): # index = 被装饰对象index函数的内存地址
time.sleep(1)
print('from index'
def home(name):
time.sleep(2)
print("welcome %s to home page" %name)
return 123
def outter(func): # func = 被装饰对象index函数的内存地址
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs) # 被装饰对象index函数的内存地址(x,y,z)
stop = time.time()
print('run time is %s' %(stop - start))
return res
return wrapper # 千万别加括号
index = outter(index) # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
home = outter(home)
# print(index)
res = home("egon") # wrapper("egon")
print(res)
res = index() # wrapper()
print(res)
装饰器的语法糖。被装饰函数的正上方,单独一行
mport time
from functools import wraps
def outter(func): # func = 被装饰对象index函数的内存地址
@wraps(func)
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs) # 被装饰对象index函数的内存地址(x,y,z)
stop = time.time()
print('run time is %s' %(stop - start))
return res
return wrapper # 千万别加括号
@outter # index = outter(index) # outter(被装饰对象index函数的内存地址) -> 返回wrapper函数的内存地址---> index = wrapper函数的内存地址
def index(): # index = 被装饰对象index函数的内存地址
"""这是index函数"""
time.sleep(1)
print('from index')
@outter # home = outter(home)
def home(name):
time.sleep(2)
print("welcome %s to home page" %name)
return 123
# res = home("egon") # wrapper("egon")
# print(res)
# res = index() # wrapper()
# print(res)
print(index.__name__)
print(index.__doc__)
无参装饰器的模板
def outter(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
@outter
def index():
print('index')
index()
以登录功能为案例:
def login(func):
def wrapper(*args,**kwargs):
name = input('username>>>: ').strip()
pwd = input('password>>>: ').strip()
if name == 'egon' and pwd == "123":
res = func(*args,**kwargs)
return res
else:
print('账号密码错误')
return wrapper
@login
def index():
print('index')
index()
叠加多个装饰器
1、加载顺序(outter函数的调用顺序):自下而上
2、执行顺序(wrapper函数的执行顺序):自上而下
def deco1(func1): # func1 = wrapper2的内存地址
def wrapper1(*args,**kwargs):
print('==========>wrapper1')
res1 = func1(*args,**kwargs)
print('end1')
return res1
return wrapper1
def deco2(func2): # func2 = wrapper3的内存地址
def wrapper2(*args,**kwargs):
print('==========>wrapper2')
res2 = func2(*args,**kwargs)
print('end2')
return res2
return wrapper2
def deco3(func3): # func3 = 被装饰的index的内存地址
def wrapper3(*args,**kwargs):
print('==========> wrapper3')
res3 = func3(*args,**kwargs)
print('end3')
return res3
return wrapper3
# index = wrapper1的内存地址
@deco1 # deco1(wrapper2的内存地址) -> wrapper1的内存地址
@deco2 # deco2(wrapper3的内存地址) -> wrapper2的内存地址
@deco3 # deco3(被装饰的index的内存地址) -> wrapper3的内存地址
def index():
print('index...')
index()
二、迭代器
1、迭代器的概念:迭代器指的是迭代取值的工具,迭代就是一个重复的过程,但是每一次重复都是在上一次的基础之上进行的,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代
2、为何要有迭代器?什么是可迭代对象?什么是迭代器对象?
#1、为何要有迭代器?
对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
#2、什么是可迭代对象?
可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
'hello'.__iter__
(1,2,3).__iter__
[1,2,3].__iter__
{'a':1}.__iter__
{'a','b'}.__iter__
open('a.txt').__iter__
#3、什么是迭代器对象?
可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
调用迭代器对象的__iter__方法得到的它自己,就跟没调用一样
调用迭代器对象的__next__方法返回下一个值,不依赖索引
可以一直调用__next__直到取干净,则抛出异常StopIteration
文件类型是迭代器对象
open('a.txt').__iter__()
open('a.txt').__next__()
#4、注意:
迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
for 循环迭代
nums_iter = iter(nums)
while True:
try:
res = next(nums_iter)
print(res)
except StopIteration:
break
1、先调用in后那个对象的__iter__方法,拿到迭代器对象
2、 res = next(迭代器对象),执行一次循环体代码
3、循环往复步骤2,直到值取干净抛出异常StopIteration,for会捕捉异常结束循环
for res in nums:
print(res)
#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
print(dic[k])
#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环
迭代器的优缺点
#优点:
- 提供一种统一的、不依赖于索引的迭代方式
- 惰性计算,节省内存
#缺点:
- 无法获取长度(只有在next完毕才知道到底有几个值)
- 一次性的,只能往后走,不能往前退
三、生成器
1、什么是生成器
#只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码,得到的返回值即生成器对象
def func():
print('====>first')
yield 1
print('====>second')
yield 2
print('====>third')
yield 3
print('====>end')
g=func()
print(g) #<generator object func at 0x0000000002184360>
有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值。yield的总结
1、把函数做成迭代器
2、对比return,可以返回多次值,可以挂起/保存函数的运行状态
2、生成器就是迭代器
生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器
g.__iter__
g.__next__
生成器就是迭代器,因此可以这么取值
res=next(g)
print(res)