• python-装饰器的简单使用


    一、介绍

    首先我们先来看一个简单的例子,在基础平台中有一个home()和tv()函数,在业务平台中调用此函数时,给出了响应的打印内容:

    基础平台:
    def home():
        print('welcome to home page')
    def tv(name):
        print('welcome to tv page')
    
    
    业务平台A: 
    home()
    tv()
    
    业务平台B:
    home()
    tv()
    

        

    但是,在后续的需求中规定,在调用此函数时,还需要进行一个用户验证

    因此程序猿小A的做法是和每个业务部门交涉,每个业务部门自己写代码,在调用基础平台的时候,先进行验证:

    基础平台:
    def home():
        print('welcome to home page')
    def tv(name):
        print('welcome to tv page')
    
    
    业务平台A: 
    #验证
    home()
    tv()
    
    业务平台B:
    #验证
    home()
    tv()

    小A当天被开除了。。。

    后来程序猿小B接手了这份工作,小B的做法是在基础平台中加入验证:

    基础平台:
    def home():
        #验证
        print('welcome to home page')
    def tv(name):
        #验证
        print('welcome to tv page')
    
    
    业务平台A: 
    home()
    tv()
    
    业务平台B:
    home()
    tv()

    小B的做法相比于小A来说,好了一点,避免了业务平台的修改,老板为了奖励小B,因此在一周后把小B开除了。。。

    因为小B改动了源代码

    此后,程序猿小C又接受了这个工作。。。

    小C说:

    写代码要满足以下下两个原则:

      封闭:已实现的功能代码不允许被修改

      开放:已实现的功能代码可以被扩展:

    因此,小C打算在此处使用了装饰器的功能(见下文)

    总结:

    装饰器本质上是一个函数,可以在其他函数不做任何代码变动的情况下,提供一些扩展的功能

    二、简单装饰器的使用

    小C对代码做出了如下修改(拿tv方法举例):

    def login(func):                   #定义了一个登录验证的方法       
        print('登录验证成功')            #假设此处就是一个验证功能
        return func                    
    
    def tv():
        print('welcome to tv page' )
    tv=login(tv)                       #对tv进行了赋值,此时还没执行tv方法,只是把该方法放入到了内存中
     
    tv()
    
    ---执行结果---
    登录验证成功
    welcom to tv page
    

    该代码是如何实现验证的呢,步骤如下:

      ①执行login(tv)时,先不执行tv()方法,只是把tv()方法到了内存中,然后执行login()

      ②在login()中进行登录验证,之后返回tv()的内存地址,此时tv()还未执行

      ③把tv()的内存地址重新赋值给tv,此时tv变量的值依旧为tv()方法的内容

      ④通过调动tv()执行tv()方法

    再经过一些细小的调整,可以写成如下的形式:

    def login(func):                        
        print('登录验证成功')
        return func                    
    
    @login
    def tv():
        print('welcome to tv page' )                   
     
    tv()

    其中, @XXX  语法,就是一个装饰器,也称为“语法糖”

    至此,一个简单的装饰器雏形已经完成

    但是,此处依旧有一个缺点,那就是 即使业务方没有调用tv(),代码中也依旧会执行login()中的验证,为了让login()中的验证

    不预先执行,因此小C继续对代码进行调整

    def login(func):
        def inner():
            print('登录验证成功')
            func()
        return inner
    
    @login       
    def tv():
        print('welcome to tv page' )
    
    tv()

    此处实现验证功能的步骤如下:

      ①调用login()方法,返回inner方法的内存地址,此时func的值为tv()内存地址即内容为:

          def tv():
               print('welcome to tv page' )

      ②把inner方法的内存地址赋值给了变量tv

      ③调用tv(),因为tv的值已经为inner的内存地址,因此调用的是inner()方法

      ④实现inner()中的验证功能

      ⑤验证成功后,执行inner()中的func(),打印出‘welcome to tv page’

    至此,一个简单的装饰器才算真正完成

    如果想在调用方法中实现带参数,可以这样写:

    def login(func):
        def inner(arg):
            print('登录验证成功')
            func(arg)
        return inner
    
    @login
    def tv(name):
        print('welcom to [%s] tv page' %name )
    
    @login
    def movie(name):
        print('welcom to [%s] movie page' %name )
    
    tv('nee')
    movie('nee')
    
    -----结果-----
    登录验证成功
    welcom to [nee] tv page
    登录验证成功
    welcom to [nee] movie page

    在上面的例子中,都是实现了在调用tv()和movie()时带入一个参数的情况的。但如果在调用tv()时需要一个参数,在调用movie()时用两个参数呢?

    因此可以使用一个动态参数的方法:

    def login(func):
        def inner(*args):                #代表动态参数
            print('登录验证成功')
            func(*args)
        return inner
    
    @login
    def tv(name,password):
        print('welcom to [%s] tv page' %name )
    
    @login
    def movie(name):
        print('welcom to [%s] movie page' %name )
    
    tv('nee',123456)
    movie('nee')
    

      

     如果再进一步,想要在调用tv()方法后,打印一个结果

    def login(func):
        def inner(*args,**kwargs):
            print('登录验证成功')
            return func(*args,**kwargs)        #注意此处的return
        return inner
    
    @login
    def tv(name,password):
        print('welcom to [%s] tv page' %name )
        return '我最帅'
    
    a=tv('nee',password=123456)
    print(a)
    
    -----结果-----
    登录验证成功
    welcom to [nee] tv page
    我最帅
    

      

     

  • 相关阅读:
    <meta>标签常用内容
    CentOS8 yum方式安装mysql8.0
    xshell上传下载文件
    CentOS8查看防火墙状态,开启/关闭防火墙
    CentOS8 yum方式安装nginx1.8
    Ant下载与配置
    List集合的方法总结
    List集合的三个实现类比较
    List集合遍历的三种方法
    JAVA如何跳出多层循环
  • 原文地址:https://www.cnblogs.com/nizhihong/p/7073512.html
Copyright © 2020-2023  润新知