装饰器函数

三元运算符乱入

'''
变量 = 条件返回True的结果 if 条件 else 条件返回false的结果
'''
a,b = 1,2
c = b if a>b else a
print(c)

装饰器

你参与的项目上线了,你写了一批函数,类似下边 (虽然很low but。。。)

def fun():
    print('jcc is a beauty')

新的需求来了,需要测试你的函数运行时间,你很快写好了。

import time
def fun():
    start = time.time()
    print('jcc is a beauty')
    end = time.time()
    return end-start

代码提交给你的leader,你被骂了,写的什么垃圾代码,去好好看看开闭原则,于是你又去苦逼的改代码,最终在你使劲全身力气之后,写出了如下代码,
你没有改变源函数,而是扩展了一个新的函数

import time
def fun():
    print('jcc is a beauty')
#扩展函数
def timer():
    start = time.time()
    fun()
    end = time.time()
    return end - start
print(timer())

但是你还有n个类似的代码,难道每一个都要再为之单独写一个timer函数?
这显然不符合高级程序员的作风,于是,你又改了你的代码,这样你就可以只扩展一个timer

import time
def fun():
    print('jcc is a beauty')
def fun1():
    print('jcc is so beautiful')
#扩展函数
def timer(f):
    start = time.time()
    f()
    end = time.time()
    return end - start
print(timer(fun))
print(timer(fun1))
View Code

为了避免再次被leader黑一脸,你把代码拿给同事看,你期待得到同时的夸奖,
 but,你还是被同事黑了一脸,你的函数被很多兄弟们调用,你难道skr大猪蹄子?让兄弟们把调用方式都修改一遍?
虽然你心里想 come on man,that is not my business(此处忽略我的语法错误,如果有的话。。),但是 你不得不重新
修改你的代码,让你的兄弟们满意,苦思冥想 终于 灵光一闪,你写出了如下代码

import time
def fun():
    print('jcc is a beauty')
#扩展函数
def timer(f):
    start = time.time()
    f()
    end = time.time()
    return end - start
 fun = timer  #你把timer函数的地址赋值给fun,你只需要调用fun()就可以实现对timer的调用
 fun(f)   #but  你忽略了timer函数需要传参,而现在fun已经不再指向原来的fun函数,你无法为之传参
View Code

于是,你又又又修改了你的代码。。。既然不能传参,那我返回一个不需要传参的函数不就ok了?你奋笔疾书写下了如下代码

import time
def fun():
    print('jcc is a beauty')
#扩展函数
def timer(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        return end - start
    return inner
fun = timer(fun)

fun()#你的兄弟们只需要按照以前的调用方式即可
View Code

此处的timer就是一个装饰器(不改变调用方式,在原有的基础上加功能),fun函数就是一个被装饰函数

语法糖???

import time
def timer(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        return end - start
    return inner
# fun = timer(fun)  只要在被装饰器上边加上@装饰器名字   就可以省略这句话
@timer
def fun():
    print('jcc is a beauty')
fun()
View Code

过了一段时间,随着你的技术不断提高,leader给你分配了一些稍微复杂的模块,
你的函数第一次有了参数(嗯?第一次?!),还有了返回值!!! 为了适应新加入的函数,你必须要修改你的装饰器了

import time
#装饰器timer
def timer(f):
    def inner(*args):
        start = time.time()
        res = f(*args) #在此接受被装饰函数的返回值
        end = time.time()
        return res #在此把被装饰函数的返回值返回
    return inner
#被装饰函数fun
@timer
def fun(*args):
    return sum(args)#没错,你写的模块就是求一系列数值和,,,并返回
# fun = timer(fun)
res = fun(1,2,3)#调用函数,接受返回值
View Code

费了老大劲的你解决了所有问题,现在的你以为你可以走遍天下了
于是你总结了装饰器的固定模式

def wapper(fun):
    def inner(*args,**kwargs):#*args,**kwargs  定义是元组,调用是被打散
        #调用函数前要做的事情
        res = fun(*args,**kwargs)  #调用函数
        #调用函数后要做的事情
        return res
    return inner

过了两天,leader说可以撤掉测试时间的代码了 ,于是你费了一上午的时间在你所有的函数上面注释掉对装饰器的调
用,长舒一口气去找leader,结果他说想在测试一下,你内心mmp,脸上不得不笑嘻嘻,难道每次都要手动操作装饰器的执行?
如果有简单的方式就好了,你深思熟虑终于想到了一个主意

import time
FLAG = False  #定义一个开关,True时执行装饰器中添加的代码,false只执行被装饰的函数,需要传入装饰器中,but,
# 装饰器有一个参数是被装饰函数,,,
#装饰器timer
def out_timer(flag):
    def timer(f):
        def inner(*args):
            if flag:
                start = time.time()
                res = f(*args)
                end = time.time()
                print(end-start)
                return res
            else:
                res = f(*args)
                return res
        return inner
    return timer
#被装饰函数fun
@out_timer(FLAG) #--->在此传入开关变量   相当与先执行了out_timer(FLAG)函数,之后返回timer 然后加上@
def fun(*args):
    return sum(args)
print(fun(1,2,3))

问题解决,可以很方便的设置是否使用装饰器
View Code

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

#装饰器1
def waper1(f):
    def inner1():
        print('waper1---before')
        f()
        print('waper1---after')
    return inner1
#装饰器2
def waper2(f):
    def inner2():
        print('waper2---before')
        f()
        print('waper2---after')
    return inner2
@waper1
@waper2
def fun():
    print(1)
fun()
View Code
#执行结果
'''
waper1---before
waper2---before
1
waper2---after
waper1---after

'''
View Code

 

posted on 2018-08-29 19:01  蒋丞丞  阅读(549)  评论(0编辑  收藏  举报