python入门基础-函数装饰器的理解

Posted jason.lv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python入门基础-函数装饰器的理解相关的知识,希望对你有一定的参考价值。

1.装饰器

# 知乎某大神是这么比喻装饰器的:内裤可以用来遮羞,但是到了冬天他就没有办法为我们御寒,聪明的人于是发明了长裤,有了长裤后宝宝再也不冷了,
# 装饰器就像我们这里说的长裤,在不影响内裤作用的前提下,给我们的身子提供了保暖的功效。
#
# 大神是将程序中原本的函数比喻成内裤,而装饰器比喻成了长裤,这样在寒冬里它们结合一起使用就给所有人带来了温暖。
#
# 装饰器本质上是一个python函数,它可以让其它函数在不改动代码的情况下增加额外的功能,并且装饰器的返回值也是一个函数对象。
# 在很多的应用场景中我们都可以用到装饰器,比如:插入日志、性能测试、事务处理等,正因为有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码,并且继续的重用。
# 那python的装饰器可以概括理解为:装饰器的作用就是为已经存在的对象增加格外的功能,并且不改变原函数的调用方式。

2.装饰器的过程

#首先我们看一段代码例子。

def func():
    print(hello word!)

func()  #我们调用函数后,可以正常打印出来 hello Word!

#比如现在我们有了一个新的需求,要在函数中增加打印函数的执行时间,那添加后的代码就是下面这段了。

import time     #加载time模块
def func():
    start = time.time() #声明变量记录函数开始执行的时间
    print(hello word!)
    end = time.time()       #声明变量记录函数结束执行的时间
    result = end  - start   #声明变量用于接收整个函数运行所耗时间
    print(result)       #打印出来函数执行的总体耗时,当前现在函数中没有什么过多的复杂代码,所以基本不存在耗时多少

#对于上面的需求我们已经实现了,但是我们是改变原函数体的结构实现的,这样在正常的开发环境中肯定是不行的,所以代码优化成下面这种。

import time

def timer():
    start = time.time()
    func()
    end = time.time()
    result = start - end
    print(result)

def func():
    print(hello word!)

timer()

#这样的话,我们就在不改变原函数体的结构情况下,增加了一项打印函数执行耗时的功能,难道这就是装饰器了?NO、NO、NO 还请继续往下看

2.1简单的装饰器

#前面我们也在没有更改原函数体的基础上增加了函数执行耗时的打印,那为什么不叫装饰器呢?因为随便没有改变函数体的结构,
# 但是我们改变了函数名的调用,之前由func()去调用就可以打印hello word,现在是调用timer()函数才能打印,所以我们的代码需要更进一步的调整。

import time

def timer(f): #实际f是func函数名
    def inner():
        start = time.time()
        f()   #实际调用的是func()
        end = time.time()
        result = start - end
        print(result)
    return inner  #将inner函数名返回

def func():
    print(hello word!)

func = timer(func)      #此时是 func = inner
func()      #此时实际调用的函数是  inner()

#那上面这行代码就可以称之为一个简单的函数体了,但是也不是很完美,因为真实的环境中肯定存在很多的函数,在大多函数都需增加函数执行耗时功能的时候。
#我们不可能在没有个函数调用前,都提前像 func = timer(func)这种声明,所以我们就要牵出另一个强大的功能“@语法糖
#@符号是装饰器的语法糖,在定义函数的时候使用,可以避免再一次赋值操作,就是说用了@语法糖可以节省上面的func = timer(func)这步操作。

import time

def timer(f):   #参数f 就是 func 或 func2 函数名
    def inner():
        start = time.time()
        f()     #实际调用的是 func 或 func2函数
        end = time.time()
        result = start - end
        print(result)
    return inner    #将inner函数名返回
@timer   #此时是 func = inner
def func():
    print(hello word!)

@timer      #此时是 func2 = inner
def func2():
    print(is func2)

func()
func2()

#上面通过@语法糖节省了func2 = inner这个过程,以后就可以在需要增加打印耗时的函数上面声明语法糖就可以了。
#上面的原函数调用都没有带上实参,那如果原函数带上了不同的实参,上面的方法肯定行不通了,所以我们需要进一步升级,这里又要用一个强大的功能了。
#要用的功能就是 *args 和 **kwargs 两个动态参数,并且要结合在一起使用,这样就可以天下无敌了

import time

def timer(f):   #参数f 就是 func 或 func2 函数名
    def inner(*args,**kwargs):
        start = time.time()
        f(*args,**kwargs)     #实际调用的是 func 或 func2函数
        end = time.time()
        result = start - end
        print(result)
    return inner    #将inner函数名返回
@timer   #此时是 func = inner
def func(a,b):
    print(hello word!,a,b)

@timer      #此时是 func2 = inner
def func2(a,b,c,d):
    print(is func2,a,b,c,d)

func(1,2)
func2(1,2,3,4)

#那上面的这个装饰器基本可以算作完善了

3.开放封闭原则

#函数在什么时候是开放的和什么时候是关闭的呢?听我娓娓道来
#(1)对扩展是开放的
    #为什么要对扩展开放呢?
    #任何一个程序,不可能在设计之初就已经想好了所有功能,而且后面不需要做任何的更新和修改,所以我们必须允许代码的扩展和添加新功能。

#(1)对修改是封闭的
    #为什么要对修改封闭呢?
    #因为我们写一个函数,很有可能影响其他已经在使用这个函数的用户,所以对修改函数是封闭的。

#装饰器完美的遵循了这个开放封闭原则。

4.装饰器的主要功能和固定结构

#(1)装饰器的主要功能
#在不改变函数调用方式的基础上在函数的前后添加功能。

#(2)装饰器的固定格式
def timer(func):    #装饰器函数,func是被装饰的函数名
    def inner(*args,**kwargs):
        ‘‘‘在被装饰函数之前要做的操作‘‘‘
        ret = func(*args,**kwargs)  #调用被装饰的函数
        ‘‘‘在被装饰函数之后要做的操作‘‘‘
        return ret
    return inner

 

以上是关于python入门基础-函数装饰器的理解的主要内容,如果未能解决你的问题,请参考以下文章

Python学习---装饰器的学习1210

Python基础装饰器的解释和用法

python闭包和装饰器的理解

Python 基础入门 5_2 function 函数

Python入门之python装饰器的4种类型:函数装饰函数函数装饰类类装饰函数类装饰类

Python入门篇之装饰器