装饰器简易版本、装饰器解决参数问题、解决返回值问题、课堂练习题、装饰器模板、多层语法糖、装饰器修复技术、课堂练习、有参装饰器、有参装饰器模板

一、装饰器简易版本

def outer(func_name):
    # func_name = index
    def get_time():
        # 1. 在函数执行之前,要记录一下此时的时间
        start_time = time.time()
        # 2. 开始执行函数
        func_name()
        # 3. 函数执行完毕之后,再次记录此时的时间
        end_time = time.time()
        # 4. 统计函数的执行时间
        print('执行了%s秒' % (end_time - start_time))
    return get_time
index=outer(index) # get_time的内存地址
index()

二、装饰器解决参数问题

def outer(func_name):
    # func_name = index
    def get_time(*args, **kwargs):
        # 1. 在函数执行之前,要记录一下此时的时间
        start_time = time.time()
        # 2. 开始执行函数
        func_name(*args, **kwargs)
        # 3. 函数执行完毕之后,再次记录此时的时间
        end_time = time.time()
        # 4. 统计函数的执行时间
        print('执行了%s秒' % (end_time - start_time))
    return get_time
index = outer(index)  # get_time的内存地址
index()
# login=outer(login)
login('jack')

三、解决返回值问题

def outer(func_name):
    # func_name = index
    def get_time(*args, **kwargs):
        # 1. 在函数执行之前,要记录一下此时的时间
        start_time = time.time()
        # 2. 开始执行函数
        res=func_name(*args, **kwargs)  # index()
        # 3. 函数执行完毕之后,再次记录此时的时间
        end_time = time.time()
        # 4. 统计函数的执行时间
        print('执行了%s秒' % (end_time - start_time))
        return res  # 才是真正的函数的返回结果
    return get_time
# index = outer(index)  # get_time的内存地址
# res=index()
# print(res)  # None

home=outer(home)
print(home())

四、课堂练习题

# 写一个认证装饰器
# 定义一个index函数,让用户输入用户名和密码,如果输入正确,就执行index函数,否则不能执行函数

'''升华:
    如果有一个函数被认证成功,后续的函数都不在认证了
'''
# 定义一个变量来存储是否认证成功
is_login={'is_login':False}

def login_auth(func_name):
    # func_name = index
    def auth():
        if is_login.get('is_login'):
            res = func_name()
            return res
        # 1. 让用户输入用户名和密码
        username = input('username:').strip()
        password = input('password:').strip()

        # 2. 要认证,判断用户名和密码是否正确
        if username == 'kevin' and password == '123':
            # 才是正常执行的函数
            res=func_name()
            is_login['is_login'] = True
            return res
        else:
            print('认证失败,不能执行函数')
    return auth

五、装饰器的固定模板

# 务必掌握 
def outer(func):
    def inner(*args, **kwargs):
        # 执行被装饰对象之前可以做的额外操作
        res = func(*args, **kwargs)
        # 执行被装饰对象之后可以做的额外操作
        return res
    return inner

六、装饰器语法糖

当我们使用上面的装饰器模版的时候,改变调用方式的那个、偷天换日的操作容易造成误导。因此我们引进语法糖的概念:

def outer(func_name):
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
"""
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用,语法糖就是上文中把装饰器调用名变成原函数的操作
"""
@outer  # func = outer(func)
def func():
    print('from func')
    return 'func'

@outer  # index = outer(index)
def index():
    print('from index')
    return 'index'

func()
index()

七、多层语法糖

多层语法糖实际应用中出现较少,但是我们也需要了解相关的运行原理:

1、先判断距离被语法糖作用的函数最近的语法糖,它的作用就是把被装饰函数放入装饰器的函数中当参数。这个时候装饰器外层的函数会返回内部函数名。

2、接下来我们判断第二个装饰器的语法糖。这个语法糖的作用也是把下方得到的函数传到第二个装饰器中去,由于最下方那个语法糖的作用我们得到了最下方那个语法糖对应的内层函数名,所以这里就是把这个内层的函数名传到第二个装饰器中,然后我们会得到第二个装饰器返回给我们它的内层函数名。

3、最上方的语法糖的原理跟第二个类似,把第二个装饰器返回的内层函数名当成参数传到最上方语法糖对应的装饰器中,这里我们会得到最上方语法糖对应的装饰器内层的函数名称,并将她和被装饰函数的名称绑定

import'''注意语法糖会将下面紧挨着的函数当作参数传递给@符号后面的函数名运行'''


def outter1(func1):     # 12.这个时候func1就接到了wrapper2的函数名了
    print('加载了outter1')     # 13.打印加载outter1
    def wrapper1(*args, **kwargs):      # 14.在创建新的wapper1 return
        print('执行了wrapper1')        # 16.打印wrapper1
        res1 = func1(*args, **kwargs)       # 17.遇到括号优先执行 这个时候的fun1是wrapper2所以直接跳到wrapper2
        return res1
    return wrapper1     # 15. 返回 wrapper1


def outter2(func2):     # 07.所以这个时候的func2就是wrapper3
    print('加载了outter2')     # 08.打印加载outter2 
    def wrapper2(*args, **kwargs):      # 09.然后定义了wrapper2 下一步return
        print('执行了wrapper2')        # 18.打印wrapper2
        res2 = func2(*args, **kwargs)       # 19.func2就是wrapper1
        return res2
    return wrapper2     # 10.这个时候返回wrapper2就是index返回了


def outter3(func3):     # 02.这个时候fun3是真的index 运行fun3函数
    print('加载了outter3')     # 03.打印加载了outter3 函数定义不用看代码函数体代码 所以下一步 return
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')        # 20.打印wrapper3
        res3 = func3(*args, **kwargs)       # 21.func3就是index跳到index
        return res3
    return wrapper3     # 04.所以这时候index的返回值就是wrapper3 这个时候wrapper就成了函数名 再次触发 outter2


@outter1        #11.这个时候index就到了outter1在运行outter1		15.这个时候就变成伪装的 index = routter1(wrapper2)
@outter2        # 06.所以这个时候wrapper3会传到outter2里面在运行
@outter3        # 01.这个时候就会把真正的index传给outter3 所以 outer3(index) 括号优先级执行	05.所以这个时候就是 wrapper3 = outter3(index)
def index():
    print('from index')     # 22.结束


index()
    
"""
多层语法糖 加载顺序由下往上
每次执行之后如果上面还有语法糖 则直接将返回值函数名传给上面的语法糖
如果上面没有语法糖了 则变形 index = outter1(wrapper2)
"""
PYTHON 折叠 复制 全屏

八、装饰器修复技术

装饰器修复技术不算重点知识,但是在面试的时候可以装逼。

这里需要先介绍一下help方法的作用:用于查看函数或模块用途的详细说明。

如果一些小白使用help方法查看我们被装饰函数的用法,会发现查看到的是装饰器函数的内容,这时候我们使用一些小手段就可以让help方法指向的内容回到原函数:

1、在装饰器函数上面加上from functools import wraps

2、并且在内层函数前加上@wraps(func_name),这里括号内写装饰器外层的参数名称就可以了。

def index():
	"""index函数 非常的牛"""
    pass
help(index)
help(len)
# 这是使用修复技术前的代码,返回的结果会是外层装饰器的内容

from functools import wraps
def outer(func_name):
    @wraps(func_name)  # 仅仅是为了让装饰器的效果更加逼真 平时可以不写
    def inner(*args, **kwargs):
        """我是inner 我擅长让人蒙蔽"""
        res = func_name(*args, **kwargs)
        return res
    return inner

@outer
def func():
    """我是真正的func 我很强大 我很牛 我很聪明"""
    pass


# help(func)
# print(func)
func()
# 这个时候我们发现代码运行后返回的是被装饰函数原本的内容

九、课堂练习题

# 判断七句print执行顺序
'''注意语法糖会将下面紧挨着的函数当作参数传递给@符号后面的函数名运行'''


def outter1(func1):     # 12.这个时候func1就接到了wrapper2的函数名了
    print('加载了outter1')     # 13.打印加载outter1
    def wrapper1(*args, **kwargs):      # 14.在创建新的wapper1 return
        print('执行了wrapper1')        # 16.打印wrapper1
        res1 = func1(*args, **kwargs)       # 17.遇到括号优先执行 这个时候的fun1是wrapper2所以直接跳到wrapper2
        return res1
    return wrapper1     # 15. 返回 wrapper1


def outter2(func2):     # 07.所以这个时候的func2就是wrapper3
    print('加载了outter2')     # 08.打印加载outter2 
    def wrapper2(*args, **kwargs):      # 09.然后定义了wrapper2 下一步return
        print('执行了wrapper2')        # 18.打印wrapper2
        res2 = func2(*args, **kwargs)       # 19.func2就是wrapper1
        return res2
    return wrapper2     # 10.这个时候返回wrapper2就是index返回了


def outter3(func3):     # 02.这个时候fun3是真的index 运行fun3函数
    print('加载了outter3')     # 03.打印加载了outter3 函数定义不用看代码函数体代码 所以下一步 return
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')        # 20.打印wrapper3
        res3 = func3(*args, **kwargs)       # 21.func3就是index跳到index
        return res3
    return wrapper3     # 04.所以这时候index的返回值就是wrapper3 这个时候wrapper就成了函数名 再次触发 outter2


@outter1        #11.这个时候index就到了outter1在运行outter1		15.这个时候就变成伪装的 index = routter1(wrapper2)
@outter2        # 06.所以这个时候wrapper3会传到outter2里面在运行
@outter3        # 01.这个时候就会把真正的index传给outter3 所以 outer3(index) 括号优先级执行	05.所以这个时候就是 wrapper3 = outter3(index)
def index():
    print('from index')     # 22.结束


index()

十、有参装饰器

当我们使用装饰器的时候,如果装饰器内部的代码需要参数的时候我们发现不能用传参的方式来添加参数了,所以我们又使用闭包函数在外层包了一个函数,打到传参的目的。

注:当我们看到语法糖后面跟着括号和参数的时候,需要先看函数名和括号内的内容,然后再应用语法糖功能,在我们运行之后会发现有参装饰器又变回了之前的普通装饰器只是多了一个局部名称空间读取变量

# 校验用户是否登录装饰器
def outer(mode):
    def login_auth(func_name):		
        # 这里我们可以看出来是用来传函数名的,不适合加参数了
        def inner(*args, **kwargs):		
            # 这里我们又可以看出来所有的参数都是加到内部被装饰函数中的,也不适合传别的参数所以就使用了闭包函数传参
            username = input('username>>>:').strip()
            password = input('password>>>:').strip()
            if mode == '1':
                print('数据直接写死')
            elif mode == '2':
                print('数据来源于文本文件')
            elif mode == '3':
                print('数据来源于字典')
            elif mode == '4':
                print('数据来源于MySQL')
        return inner
    return login_auth
'''当装饰器中需要额外的参数时>>>:有参装饰器'''

"""
函数名加括号执行优先级最高 有参装饰器的情况 
    先看函数名加括号的执行
    然后再是语法糖的操作
"""
@outer('1')
def index():
    print('from index')
index()

@outer('2')
def func():
    print('from func')
func()
# 如果我们不想使用装饰器功能了,就把语法糖部分的代码注释掉就可以正常运行了。

十一、有参装饰器模板

def outter(add_n):
    def middle(func):
        def inner(*args, **kwargs):
            # 这里写一些代码需要参数的那种,把最外层的add_n用进来就可以了
            res = func(*args, **kwargs)
            return res

        return inner

    return middle


@outter('参数')
def index():
    pass
posted @   吴仁耀  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
  1. 1 原来你也在这里 周笔畅
  2. 2 世间美好与你环环相扣 柏松
  3. 3 起风了 吴青峰
  4. 4 极恶都市 夏日入侵企划
极恶都市 - 夏日入侵企划
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 王星

作曲 : 灰鸿啊/皮皮

编曲 : 夏日入侵企画

制作人 : 邢硕

节奏吉他 : 肯尼

主音吉他 : 张伟楠

贝斯 : 皮皮

鼓 : 海鑫

和声 : 邢硕

音效制作 : 邢硕

录音 : 邢硕/夏国兴

混音 : 于昊

特别鸣谢 : 张伟楠

这城市的车流和这地表的颤抖

像一颗石子落入地心之后泛起的温柔

暗涌

河水流过转角她的楼

被梦魇

轻声呓语唤醒身后的幼兽

失效感官焦灼只剩下

麻木愚钝无从感受

共同支撑全都瓦解

只是我们现在都

已忘记到底是

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去陈旧的还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

眼看这情节开始变旧

所有的城池已失守

最终无法占有

无眠辗转

伴着人间破碎的旧梦

像繁星

退却后只剩下混沌的夜空

炙热

掩盖风声鹤唳的担忧

把所有失落无助反手推入

无尽的白昼

失效感官焦灼只剩下

麻木愚钝无从感受

共同支撑全都瓦解

只是我们现在都已经忘记到底是

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

眼看这情节开始变旧

所有的城池早已失守

惶恐难以接受

缠绵往复不肯放手

最终无法占有

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁 灭 即 拯 救

谁掠夺春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

明知城池已失守

缠绵往复不肯放手

最终无法占有

点击右上角即可分享
微信分享提示