函数__装饰器

一.装饰器。

一.装饰器.

 装饰器: 在目标函数前和后插入一段新的代码,不改变原来的代码.装饰器是对原来基础功能的扩展和开放,又不变动原代码,所以比较安全.

装饰器的本质是一个闭包。什么是闭包,就是内层函数对外层函数的变量的引用。

装饰器语法

 

# 通用装饰器写法:
# python里面的动态代理.
# 存在的意义: 在不破坏原有函数和原有函数调用的基础上. 给函数添加新的功能
def wrapper(fn): #  fn是目标函数.
    def inner(*args, **kwargs): # 为了目标函数的传参
        '''在执行目标函数之前.....'''
        ret = fn(*args, **kwargs) # 调用目标函数, ret是目标函数的返回值
        '''在执行目标函数之后....'''
        return ret  # 把目标函数返回值返回. 保证函数正常的结束
    return inner

@wrapper  # target_func = wrapper(target_func) #此处的wrapper 一定记住:是不加括号的,不是调用!!!
def target_func():
    pass

# target_func = wrapper(target_func) # 此时fn就是target_func
target_func() # 此时执行的是inner

 

def outer(a):
    b = 1
    def inner():
        print(a + b)
    return inner  
# 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
if __name__ == '__main__':
inner
= outer(1) inner()

 

 

 

下面是简易版装饰器
def
play(username, password): print("双击lol") print("登录", username, password) print("选择狂战士") print("进草丛") return "月之光芒" def xiaoxiaole(qq): print("登录qq账号") print("消消乐") def wrapper(fn): # fn = play def inner(*args, **kwargs): # 无敌传参 接受到的是元组 ("alex", 123) print("开挂") ret = fn(*args, **kwargs) # 接受到的所有参数. 打散传递给正常的参数 return ret 接收函数的返回值 return inner play = wrapper(play) # play = inner ret = play('alex',"123") print(ret) 输出结果: 开挂 双击lol 登录 alex 123 选择狂战士 进草丛 月之光芒

带参数的装饰器(装饰器的开关).

def wrapper_out(flag): # 装饰器本身的参数
    def wrapper(fn): # 目标函数
        def inner(*args, **kwargs): # 目标函数执行需要的参数
            if flag == True:  #如果开关为False,就不进行函数的装饰
                print("问问金老板. 行情怎么样啊") #执行函数之前
                ret = fn(*args, **kwargs) # 在执行函数本身
                print("金老板骗我. 恨你") #执行函数之后
                return ret
            else:
                ret = fn(*args, **kwargs)  #执行函数本身
                return ret
        return inner
    return wrapper


# 语法糖 @装饰器
@wrapper_out(True) # 先执行wrapper_out(True) 返回一个装饰器   再和@拼接  @装饰器
def yue(): # 被 wrapper装饰
    print("走啊. 约不?")

yue()

 

解释1:
不理解为何会变?:
写完一个函数之后,不指定对象的调用它,你print这个函数,打印出来的内容,除了函数里的,一定还有它自己的返回值,说白了,此时的调用完之后,函数已经变成了它自己的返回值
解释2:
此时,这里变成了@wrapper,是个语法糖,就是python设计的语法上的简写,他和后面定义的函数,合在一起等值于  b=wrapper(b)(此时的函数名b就等于inner函数名,再调用就是调用的inner()函数)
解释3:
如果这里的参数True改为False,那么就无法执行该函数,会报错,这里的Alex(True)是让函数正常执行,执行完了,会变成该函数的返回值 → wrapper,而@wrapper下面定义的函数意味着,就是wrapper函数括号里参数,
而你再用这个参数名接收返回值,该函数名就变成了返回值,你之后再调用的实际是装饰器内部的函数,如果你想关闭装饰器,就把True,改为Flase,就可以了

装饰器的应用:

# 装饰器在登陆验证方面的应用.
flag =False   #没登陆的状态为False
def login():   #此函数为登陆函数,只有登陆成功,才会显示成功登陆的状态(flag = True)
    global flag
    zhanghao =input("请输入账号:")
    mima = input("请输入密码:")
    if zhanghao=="alex" and mima=="123":
        flag = True
        return "登陆成功"
    else:
        print("对不起,输入有误.")
        exit()
def zhuangshi1(a):
     def zhuangshi(fn):  #装饰器函数
        def inner(*can1,**can2):
                while 1:
                    if flag == True:
                        print("装饰器把你装饰了一番,你NB了")
                        ret = fn(*can1,**can2)
                        return ret,"从此人生达到巅峰!" #此处有多个返回值,会变成元组形式返回
                    else:
                        print("对不起,您还没登陆.")
                        login()
        return inner
     return zhuangshi
@zhuangshi1(True)
def wangzhe(a,b):
    print("玩家",a,"进入了游戏")
    return "得到月之光芒剑"
a = wangzhe("alex","123456")
print(a)
打印结果为:
对不起,您还没登陆.
请输入账号:alex
请输入密码:123
装饰器把你装饰了一番,你NB了
玩家 alex 进入了游戏
('得到月之光芒剑', '从此人生达到巅峰!')

 多个装饰器装饰同一个函数:

def wrapper1(fn):
    def inner(*args, **kwargs):
        print("装饰1111111")
        ret = fn(*args, **kwargs)
        print("装饰1111111")
        return ret
    return inner

def wrapper2(fn):
    def inner(*args, **kwargs):
        print("装饰2222222")
        ret = fn(*args, **kwargs)
        print("装饰2222222")
        return ret
    return inner

#就近原则
@wrapper1 #后被它装饰
@wrapper2 #先被此装饰器装饰
def func():
    print("我是幸运的func")
func()
输出结果为:
装饰1111111
装饰2222222
我是幸运的func
装饰2222222
装饰1111111

 

posted @ 2018-12-17 08:55  Tank-Li  阅读(189)  评论(0编辑  收藏  举报