python菜鸟之——小谈装饰器

装饰器介绍

假设有一个显示鱼数量的函数:

def info(fishnum):
    print('The fish number is %s' % fishnum)

#调用    
info(2002)

现在需要对此函数添加一个补充信息:说明是在河里的鱼的数量,添加一个 print(‘In river’),但是不能对原来的函数进行任何一点修改 ,如何实现?

有了!!因为python的高级函数可以用函数作为传入参数。可以新建一个高级函数info_before,将info函数作为参数传入info_before(info);
高级函数的函数体内因该是这样的:在执行完需要的操作后,在执行函数参数info:

def info_before(info):
     需要的操作
     info()

然后再将info_before函数执行结果赋值给info函数就可以了:info=info_before(info),这样就不影响info的调用了

操作如下:

##原来的函数
def info(fishnum):
    print('The fish number is %s' % fishnum)

##新定义的高级函数
def info_before(func):
    print('In river \r')
    func()

##覆盖原来的函数
info=info_before(info)

看起来可行,执行下 info(2002) 试一试:

出错了!!!

原因:info=info_before()即执行了info_before()高级函数,但是高级函数内的函数体中的info()已经执行了info函数,所以,info接收到的是一个print(‘In river \r’)信息和info()函数的运行结果,又因为info()函数没有参数,所以报错。
而我们需要的返回值是一个函数才对!(之后还要调用),修改如下:

##原来的函数
def info(fishnum):
    print('The fish number is %s' % fishnum)

##新定义的高级函数
def info_before(func):
    print('In river \r')
    #修改返回值是函数
    retrun info

##覆盖原来的函数
info=info_before(info)

执行下 info(2002) 试一试:

看起来还不错

但是,当不执行 info(2002) 时,发现有个问题:只要进行了 info=info_before() ,就会自动执行 print(‘In river \r’) 这句命令

如果不写这句,那么后面将不能使用info()调用 新定义的高级函数(改为 info_before(info)调用),这样就影响了原来函数的调用

有没有新的办法?

对了,可以在高级函数内在嵌套一个函数,然后将所有操作放在内嵌函数内,这样就不会在执行高级函数时赋给原来函数时 info=info_before() ,自动执行高级函数内的操作了:

##原来的函数
def info(fishnum):
    print('The fish number is %s' % fishnum)

##新定义的高级函数
def info_before(func):
    #再嵌套一层内部函数,因为原函数info有变量,这里qure函数也应该需要变量,因为之后会将qure函数赋给info来覆盖原函数
    def qure(avrg):
        print('In river \r')
        #此时应该返回的是info()的执行结果,因为之后info=info_before()操作实际是将qure函数赋给了原函数info,之后调用原函数实际上是调用了qure函数,此时应该返回info()的操作结果
        func(avrg)#闭包
    #返回qure函数给原函数
    retrun qure

##覆盖原来的函数,用qure函数覆盖了info函数
info=info_before(info)

执行下 info(2002) 试一试:

完美!!

上述高级函数info_before就是装饰器的定义

  • 装饰器详细介绍

    • 在info函数前使用@info_before就表示调用装饰器info_before,相当于:info=info_before(info)表达式。即在执行info前先执行info_before下的内容
    • 装饰器小结:
    • 装饰器是为了在不影响原函数的代码结构和调用的基础上,给原函数新添加某些操作或者功能的高级函数
    • 装饰器输入参数为函数是为了先执行定义的操作,在执行参数函数
    • 装饰器内置函数是为了覆盖原函数的时候不执行定义的操作,内置函数参数使用*avrg,**avtg2 动态参数满足原函数所有参数情况,内置函数的函数体内部原函数执行时,参数也为*avrg,**avtg2。内置函数里面执行原函数时需要使用return避免原函数有返回值无法返回
    • 装饰返回为函数是为了不影响原函数的调用
    • 装饰器最终在python中的表现为:
    
    #装饰器定义
    
    def info_before(func):
    
    #qure函数使用动态参数满足原函数任何参数情况
    
    def qure(*avrg,**avtg2):
        print('In river \r')
        #注意func参数和qure参数,使用return避免原函数有返回值无法返回
        return func(*avrg,**avtg2)
    
    #返回qure函数给原函数
    
    return qure
    
    
    #装饰器调用
    
    @info_before
    def info(fishnum):
    print('The fish number is %s' % fishnum)
    
    info(2002)
  • 含参数的装饰器

    • 装饰器info_before新增的操作只是print操作,那么如果是很复杂的代码呢?我们可以将print操作放在一个函数b_fun中,然后在把函数b_fun传入装饰器@info_before(b_fun)
    • @info_before(b_fun)含参数的装饰器,只需要将操作方法写在函数中即可,对于装饰器可以使用一个相同的装饰器定义模板,因为不同的装饰器其实就是在原函数之前/之后添加的操作不同而已,对于装饰器本身,都是相同的结构
    • 综上,装饰的实际使用应该是这样
    • 有一个装饰模板 @Filter(fun1,fun2) ,它规定了可以传入2个函数参数,第一个函数是执行原函数之前的一些操作方法,第二个函数是执行原函数之后的一些操作方法。那么在使用装饰器时,我们只需要定义fun1和fun2就可以了,至于如何定义装饰器,已经被模板@Filter(fun1, fun2)定义好了。

    • 附:Filter模板(已经定义好了,只需要我们定义好函数fun1和fun2 然后传入装饰器就行)
    def Filter(fun1,fun2):
    def outer(main_func):
        def wrapper(request,kargs):
    
            before_result = fun1(request,kargs)
            if(before_result != None):
                return before_result;
    
            main_result = main_func(request,kargs)
            if(main_result != None):
                return main_result;
    
            after_result = fun2(request,kargs)
            if(after_result != None):
                return after_result;
    
        return wrapper
    return outer

    调用装饰器

    
    #装饰器@Filter:在Index函数之前先执行Before函数,在Index函数之后,在执行After函数
    
    @Filter(Before, After)
    def Index(request,kargs):
    print 'index'

猜你喜欢

转载自blog.csdn.net/chuxuan909/article/details/79224539
今日推荐