Python学习之-----装饰器

python的装饰器是为了实现开闭原则而生的

一旦投入使用的代码就不能做修改了(封闭原则)

比如:
  我写了几个方法,现在老板让我在这几个方法的基础上,计算一下方法执行消耗的时间,因为现在这几个方法,有很多客户已经在使用了,所以不能对原函数做修改(封闭原则),而且又得能计算消耗的时间,因为可能要对很多函数做修改,所以最好找一个通用简单的方法

这时候,装饰器就是最好的选择了

比如,我已经写了两个func():

    def func1():
        print("func1  is  running.....")
        time.sleep(1)
    def func2():
        print("func2  is  running.....")
        time.sleep(2)

现在我要用装饰器对现在已有的这两个函数做修改,增加其原有功能

在使用之前,必须要知道python的三个知识点
1.作用域
2.高阶函数
3.闭包

首先,我们定义一个专门用来计算函数消耗时间的函数spend_time,传入的参数就是我们要计算时间的函数x

    def spend_time(x):  #x为我们要计算的函数---(高阶函数特性  函数可以作为参数)
        start = time.time() #记录开始时间
        x() #要计算的函数执行
        end = time.time()#记录结束时间
        print("spend    %   秒"%(end - start))


    spend_time(func1)
    spend_time(func2)
  #执行结果:
    #func1  is  running.....
    #spend   1.0000572204589844 秒
    #func2  is  running.....
    #spend   2.0001144409179688  秒

这样写确实可以实现功能了,而且也不会太麻烦,但是只能调用spend_time这个方法才可以计算出消耗时间,有什么办法可以让我们调用func1()或者func2()就可以实现呢???

我们对spend_time函数做一下修改

    def spend_time(func):
        def inner():
            start = time.time() #记录开始时间
            x() #要计算的函数执行
            end = time.time()#记录结束时间
            print("spend    %   秒"%(end - start))
        return inner #最后把inner这个函数返回(高阶函数特性,闭包)

这时,我们就可重新给func1和func2赋值

    func1 = spend_time(func1)#这里的spend_time(func1)  实际上是inner函数
    func2 = spend_time(func2)#同上

这个时候直接使用func1和func2函数的结果就和之前使用spend_time()是一样的了

    func1()
    func2()
    #执行结果:
    #func1   is   running...
    #spend   1.0000574588775635 秒
    #func2   is   running...
    #spend   2.0001144409179688 秒

这就是装饰器....

然而,每次在使用装饰器的时候都要给原有函数重新赋值是不是相当麻烦?
每次都要调用
func1 = spend_time(func1)
func2 = spend_time(func2)
是一件必要且有规律可寻的重复的工作
python已经很好的替我们做了这个工作

在我们定义了spend_time函数的基础上,在要修改的函数上面加上@spend_time 这个注解,就可以实现类似

func1 = spend_time(func1)这样的赋值代码了

def spend_time(fun):
    def inner():
        starttime = time.time()
        fun()
        end_time = time.time()
        print('spend   %s ' % (end_time - starttime))
    return inner


@spend_time
def fun1():
    print('func1   is   running...')
    time.sleep(1)


@spend_time
def fun2():
    print('func2   is   running...')
    time.sleep(2)


# fun1 = spend_time(fun1)
# fun2 = spend_time(fun2)

fun1()
fun2()

执行结果
func1   is   running...
spend   1.0000574588775635 
func2   is   running...
spend   2.0001144409179688 

回到最初的起点:

我们要给每个函数增加一些功能的话只需要将功能定义出来,在要修改的函数上加上

@装饰器名称就可以了,简单粗暴

拓展--装饰设计模式

带参数的装饰器

我们用一个例子来学习

需求:我们需要做一个登陆系统,如果用户没有登录的话就跳转登录并可以选择微博登录或者微信登录,如果已经登录了,就跳转目标页面(主页或者产品页)

** 需求本质内容实际上是跳转目标页面,在这个基础上增加登录功能,并在登录功能基础上增加登录类型选择 **

首先我们需要一个全局变量来存储用户的登录状态,

isLogin = False

其次,定义主要跳转函数

def turn_to_home():
    print('跳转主页面.....')
def turn_to_prod():
    print("跳转产品页......")

在类似的方法中增加功能,我们使用装饰器

def check_login(func): #传入具体的跳转操作
    def inner():
        global isLogin #在这里我们需要声明这里的登录判断flag是全局的变量
        if isLogin:
            print("用户已经登录了....")
            func() #执行具体的跳转操作
        else:
            print("用户还未登陆,去登陆........")
            print("登录成功")
            func() #登录成功,执行具体跳转操作
            isLogin = True  #将用户登录状态修改为已登录
    return inner

这样,一个带有登录判断功能的装饰器就写好了
我们重新定义具体登录操作的函数

@check_login
def turn_to_home():
    print('跳转主页面.....')
@check_login
def turn_to_prod():
    print("跳转产品页......")

turn_to_home()
turn_to_prod()


#运行结果:
#用户还未登录,去登陆......
#登录成功
#跳转主页面......
#用户已经登录了....
#跳转产品页

现在,登录判断功能已经添加了,还需要添加一个登录类型区分

我们再定义一个函数,并且将之前的装饰器作为他的局部函数和返回参数放进去,这个函数的参数就可以被我们用来做登录类型区分来使用了

def check_login_type(login_type):
    def check_login(func): #传入具体的跳转操作
        def inner():
            global isLogin #在这里我们需要声明这里的登录判断flag是全局的变量
            if isLogin:
                print("用户已经登录了....%s登录" % login_type)
                func() #执行具体的跳转操作
            else:
                print("用户还未登陆,去登陆........跳转%s登录"%login_type)
                print("登录成功")
                func() #登录成功,执行具体跳转操作
                isLogin = True  #将用户登录状态修改为已登录
        return inner
    return check_login

我们再重新定义具体跳转方法的时候就可以将登录类型作为装饰器的参数传入

@check_login_type("微博")
def turn_to_home():
    print('跳转主页面.....')
@check_login_type("微信")
def turn_to_prod():
    print("跳转产品页......")
turn_to_home()
turn_to_prod()

#执行结果:
#用户还未登录,去登陆......跳转微博登录
#登录成功
#跳转主页面......
#用户已经登录了....
#跳转产品页
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 背景 虽然之前看过装饰器的相关内容,但是今天想起来,一直没有好好总结一下,所以特地记录下关于装饰器的一系列用法。要...
    楼上小宇阅读 696评论 0 3
  • Josh Kaufman (用20小时学习任何事物) 学习新知识,充满好奇心通过不断试错,学习,最终擅长这个技能。...
    不会停的蜗牛阅读 640评论 0 3
  • 终没能抵抗得了那一幅幅美如画,我也跟着追剧了,终于在今日把《三生三世十里桃花》全部看完了。朋友说:难得你还会追剧。...
    江之蓝语阅读 485评论 0 1
  • 你敢不敢 承认自己不勇敢, 卸下虚与委蛇的妆, 在午夜梦回的时候, 看看镜中自己憔悴的模样? 你敢不敢...
    木叶丶飘阅读 295评论 8 1