装饰器与语法糖

1、什么是装饰器
    装饰器就是装饰别人的工具,具体是指为被装饰者添加新功能
    装饰器-》函数
    被装饰者-》函数

2、为何要用装饰器
    装饰器的核心思想:(开放封闭原则)
        在不修改被装饰者源代码以及调用方式的前提下,为被装饰者添加新功能

3、如何实现装饰器
    可以用闭包函数去实现装饰器

被装饰者
import time

def index():
    print('welcome to index page')
    time.sleep(3)

index()

方案一:问题-》修改了被装饰者的源代码
import time

def index():
    start = time.time()
    print('welcome to index page')
    time.sleep(3)
    stop = time.time()
    print(stop - start)

index()


方案二:问题-》会造成代码冗余
import time

def index():
    print('welcome to index page')
    time.sleep(3)

start = time.time()
index()
stop = time.time()
print(stop -start)

start = time.time()
index()
stop = time.time()
print(stop -start)

# 方案三:问题-》修改了被装饰对象的调用方式
import time

def index():
    print('welcome to index page')
    time.sleep(3)

def wrapper(func):
    start = time.time()
    func()
    stop = time.time()
    print(stop -start)

wrapper(index)


# 方案四:我们用wrapper函数赋值给原函数名index,wrapper应该与原函数保持一致,但是现在的问题是不一致
import time

def index():
    print('welcome to index page')
    time.sleep(3)

def outter(func):  # func = 最原始那个index函数的内存地址
    def wrapper():
        start = time.time()
        func()
        stop = time.time()
        print(stop -start)
    return wrapper

index = outter(index)  # f=outter(最原始那个index函数的内存地址)
                   # f=函数wrapper的内存地址
# print(f)
index()


方案四:让wrapper的参数与返回值与被装饰者保持一致
import time

def index(x,y,z):
    print('welcome to index page',x,y)
    time.sleep(3)
    return 123


def outter(func):  # func = 最原始那个index函数的内存地址
    def wrapper(*args,**kwargs):
        start = time.time()
        res = func(*args,**kwargs)
        stop = time.time()
        print(stop -start)
        return res
    return wrapper

index = outter(index)  # f=outter(最原始那个index函数的内存地址)
                   # f=函数wrapper的内存地址


res = index(111,222,333)  # res = wrapper(111,222,333)
print(res)

二、装饰器语法糖

# 装饰器语法糖:在不修改源代码情况下,为其新增功能称之为装饰器语法糖。

import time
from functools import wraps   # wraps:别人写好的装饰器模块

def outter(func):
    @wraps(func)
    def wrapper(*args, **kwargs):   # 可变长参数
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
        return res
    return wrapper


@outter  # index = outter(index)
def index(x, y, z):
    """index函数的文档注释"""
    print('welcome to index page', x, y)
    time.sleep(3)
    return 123


# res = index(111, 222, 333)
# print(res)

# print(index)
help(index)

三、装饰器模板

# 装饰器模板
def outter(func):
    def wrapper(*args,**kwargs):
        print('hello')
        res = func(*args,**kwargs)
        return res
    return wrapper

@outter
def index():
    print('index=========>')

index()  # 调用

# 案例
def auth(func):
    def wrapper(*args,**kwargs):
        username = input('username>>>: ').strip()
        password = input("password>>>: ").strip()
        if username == 'meng' and password == '123':
            res = func(*args,**kwargs)
            return res
        else:
            print("认证失败")
    return wrapper

@auth
def index():
    print('index=========>')

index()

四、迭代器

1、什么是迭代器
    迭代器指的是迭代取值的工具
    什么是迭代???
        迭代是一个重复的过程,但是每一次重复都是基于上一次结果而继续的

    dic = {'k1':111,'k2':2222,'k3':33333}
    def foo(xxx):
        i = 0
        while i < len(xxx):
            print(xxx[i])
            i += 1
    foo(dic)

2、为何要用迭代器
    1.为了找到一种统一迭代取值方案(适用于str、list、tuple、dict、set,文件对象)
    2.节省内存

3、如何用迭代器
    可迭代的对象iterable:
        内置有__iter__方法的对象(str、list、tuple、dict、set,文件对象)
    迭代器对象iterator:
        内置有__iter__方法:生成一个可迭代对象
        内置有__next__方法:取值
        
# 可迭代对象:
    "abc".__iter__()    
    [1,23].__iter__()
    (1,2,3).__iter__()
    {'k1':111}.__iter__()
    {1,2,3}.__iter__()
    f = open('a.txt',mode='wt')
    f.__iter__()
    
案例1:代码冗余
    dic = {'k1':1111,'k2':2222,'k3':3333}
    iter_dic = dic.__iter__()  # iter_dic=iter(dic) 变成一个可迭代对象

    print(iter_dic.__next__())  # print(next(iter_dic))
    print(iter_dic.__next__())
    print(iter_dic.__next__())   # 只能去列表的3个值,取完再取会报错。
    # print(iter_dic.__next__())  # 报错

    new_iter = dic.__iter__()   # 从新取只能在新建一个可迭代对象
    print(new_iter.__next__())  # 在从新取值
    
案例2:用捕捉异常让代码继续执行
dic = {'k1': 1111, 'k2': 2222, 'k3': 3333,'k4':4444,'k5':5555}
def did():
    iter_dic = iter(dic)
    while True:
        try:
            print(next(iter_dic))
        except StopIteration:
            break
did()

for x in dic:  # for循环原理:迭代器对象
    print(x)

自定义迭代器

# yield可以返回多次值

def func():
    print('hello1')
    print('hello1')
    yield 111
    print('hello2')
    print('hello2')
    yield 222
    print('hello3')
    print('hello3')
    yield 333
    print('hello4')
    print('hello4')
# 函数内但凡出现yield语法,我们再调用函数就不会立即触发函数体代码运行,会返回一个生成器对象,生成器对象就是一种自定义的迭代器
g = func()
print(g)  # 会打印出111
posted @ 2021-11-18 11:57  迷恋~以成伤  阅读(90)  评论(0)    收藏  举报