• python基础-第五篇-5.3装饰器


      小白发呆的看着窗外,同事们陆陆续续的地来到公司,想起算法,小白就飘飘然了。突然后面传来一声呼唤,原来是小刘!

      小刘:不好意思啊!堵车了,就来晚了点,不耽误你的时间,咱们就开启的今天的培训内容吧!

      小白连忙说:没事,可以开始啦!

    函数内存与执行函数

      小刘:那我给你看一段代码,你看看会得到什么结果

    def f1():
        return 'F1'
    
    x = f1()
    print(x)
    
    x2 = f1
    print(x2)
    

       小白看了看,很快说出了x的输出值为‘F1’,但是看到x2这里,小白就有点想不通,小白就执行了一遍

      

      小白还是看不懂,就问小刘这x2到底打印的是什么玩意啊?

      小刘笑了笑:这可神奇了,叫做函数内存地址,看着哈,我给这这玩意加点东西

    def f1():
        return 'F1'
    
    x = f1()
    print(x)
    x2 = f1
    print(x2)
    ret = x2()
    print(ret)
    

       小刘:我只是把f1赋值后的x2加了个括号,最后的结果和f1函数执行的结果一样,神奇吧?

       小刘:这是我画的原理图,你看看

      

      小白若有所悟的点点头,那我这样这样做,结果那是一样一样的?

    def f1():
        return 'F1'
    
    x = f1()
    print(x)
    x2 = f1
    ret = x2()
    print(ret)
    x3 = x2
    ret2 = x3()
    print(ret2)
    x4 = f1
    ret3 = x4()
    print(ret3)
    

        小刘:是的,你只要记住,函数名加括号就是执行函数,没加就是函数内存地址就可以了

      小白点点头

    当函数名也来做函数参数时

      小刘:既然函数的内存地址都能赋给多个变量,那它做可以做为函数参数传入到函数体中去么??

      小白含糊其辞地回来了个:应该可以吧

      小刘:先给看个例子吧,你先想一下结果什么?

    def login(func):
        print('passed user verification...')
        return func
    
    def tv():
        print('welcome [%s] to tv page')
    
    tv = login(tv)
    

       小白手停不下来,又开始画起来了

      

      小白连忙答道:执行了login函数,打印了‘passed..ver...’,tv这个函数名指向的内存地址没有变并且tv函数不执行。

      小白回答到这,又不由说到:走这么一个大弯,回来还是原样子,这个做难道有很大用处??

      小刘微微一笑:你有这样的疑问!很正常,那我直接告诉你它的用处吧,在不修改源码的情况,可以增加额外的功能,比如说在基本功能上我要加个用户权限管理,login函数就是对这个进行验证的,那问你--如果上面要执行tv函数,你怎么做?

      小白:简单,在下面加个调用函数--tv()

      小刘点点头,那我们回到刚才那个案例上来,假如你是那基层平台的管理者,你觉得这样添加功能,你满意吗?

      小白:满意!不修改源码下实现了额外的功能!

      小刘:如果是我,我还是不满意,因为我要为其他的业务部门人员使用平台而考虑,以前他们只要调用tv()就行,现在要先写tv = login(tv),再写tv()才达到自己的目的,你不觉得这样添加了他们的负担吗?

      小白:是啊,我怎么没想到呢?

      小刘:好!冲着这点,我给到你这个方案,你看看

    def login(func):
        print('passed user verification...')
        return func
    
    @login
    def tv():
        print('welcome [%s] to tv page')
    
    tv()
    

       小刘:那我也明确告诉你,@login的作用等同于tv=login(tv),你看最终会得出什么结果?

      小白:既然@有这种效果,那打印passed user verification...  welcome [%s] to tv page这两句

      小刘:嗯!而且我告诉你这玩意叫做装饰器,作用就是把装饰器下面的函数--函数名当参数传给装饰器函数,不过刚才我给你这个方案还一个弊端,你把执行tv()去掉试试看?

      小白对得出结果也表示惊奇,连摇头表示不懂。

      小刘给了一张图给小白看

      

      小白看到图后,才想到装饰器等同就是执行了login函数

      小白:那我们应该怎么处理这种弊端呢?

      小刘:那我问问你,python解释器遇定义函数是什么情况?

      小白:把函数刷到内存里,不执行

      小刘:好!那我们就利用这一点,给那个装饰器函数里在嵌套一个函数!  

      小白好像有些恍然大悟,但还是不知道怎么做

      小刘:小白!我给你看这个例子

    def login(func):
        def inner():
            print('passed user verification...')
            return func
        return inner
    
    @login
    def tv():
        print('welcome [%s] to tv page')
    

       小刘;你执行一下,看达到我们的效果没有?

      小白欢喜的回到:我们做到了

      小刘:别告诉的太早了,还有问题,你执行一下看看,加个tv()

      小白加了tv()执行后惊讶地发现,真正tv的功能根本没有执行,小白一脸疑惑!

      小刘:小白!你来看看这张图

      小刘:你看,我们应该怎么改进,让其执行原来tv函数呢?

      小白看着图想了想,不应该return tv内存地址,应该在那写成tv()执行函数

      小刘:就按你说的,试一下。

      

    def login(func):  #tv
        def inner():
            print('passed user verification...')
            func()
        return inner
    
    @login  #tv = login(tv)
    def tv():
        print('welcome [%s] to tv page')
    
    tv()
    

       小刘:不错哦!实现了哦!

    给装饰器加参数

      小刘:业务部门调用函数是不是会给装饰器传参数?那如果要加参数应该加到哪呢?

      小白想了想

      

      小刘看着小白画的图,哈哈大笑!悟性高!

    def login(func):  #tv
        def inner(arg1,arg2):
            print('passed user verification...')
            func(arg1,arg2)
        return inner
    
    @login  #tv = login(tv)
    def tv(arg1,arg2):
        print('welcome [%s] to [%s] tv page'%(arg1,arg2))
    
    tv('alex','江西卫视')
    

       小刘:小白!是不是有不同的业务用我们的平台,那他们是不是有可能往装饰器里传的参数个数都有可能不同?

      小白:嗯嗯!

      小刘:那怎么解决这个需求呢?

      小白想了又想,支支吾吾的回答了个:难道要用函数里的动态参数??

      小刘:没错!那我们来看看怎么改进吧

    def login(func):  #tv
        def inner(*args,**kwargs):
            print('passed user verification...')
            func(*args,**kwargs)
        return inner
    
    @login  #movie = login(movie)
    def movie(arg1):
        print('welcome [%s] to movie page'%arg1)
    
    @login  #tv = login(tv)
    def tv(arg1,arg2):
        print('welcome [%s] to [%s] tv page'%(arg1,arg2))
    
    tv('alex','江西卫视')
    print('*'*25)
    movie('eric')
    
    结果为:
        passed user verification...
        welcome [alex] to [江西卫视] tv page
        *************************
        passed user verification...
        welcome [eric] to movie page
    

       小白:实现了!

      小白乐地得都合不上嘴了!

      小刘:好了!装饰器大部分内容给你讲完了,最后剩下那点内容就算你回家的任务吧,就是多个装饰器运行流程,以你的领悟能力,应该没问题。

      小刘:另外就多个装饰器,我总结了两句话,在执行过程中,你结合这两句话去理解:

                              1.多个装饰器在调用时,从外向里

                        2.装饰器的封装是从里向外的

      小白:好!没问题!小刘!你辛苦了

      小刘:应该的!那回去吧!

                                                       欢迎大家对我的博客内容提出质疑和提问!谢谢

                                                                                 笔者:拍省先生

  • 相关阅读:
    SQL Server 索引结构及其使用(三)
    SQL Server 索引结构及其使用(一)
    存储过程中的top+变量(downmoon)
    全文索引
    基本DDL 语句之Create Database(downmoon)
    SQL Server 索引结构及其使用(二)
    SQL Server 索引结构及其使用(四)
    前触发器和后触发器简介(downmoon)
    MongoDB学习笔记
    1. 索引的建立和运用
  • 原文地址:https://www.cnblogs.com/xinsiwei18/p/5564735.html
Copyright © 2020-2023  润新知