装饰器,迭代器,生成器

一、装饰器

无参装饰器的实现

如果想为下述函数添加统计其执行时间的功能

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)
posted @ 2020-12-30 15:32  小绵  阅读(50)  评论(0编辑  收藏  举报