Python装饰器

 

  本篇我们介绍关于装饰器(Decorator)的基本知识,故我们就以什么是装饰器,为什么要使用装饰器,以及如何来实现装饰器这三个部分来介绍。

一、什么是装饰器?

  装饰器(Decorator):首先我们需要知道装饰器本身就是一个函数,而这个函数存在的意义就是为其他函数添加附加功能的。

  而从某种程度上来说:装饰器并非一个功能特性,它只是一个语法糖,因为从本质上来讲:它实现的是将一个函数或者对象作为参数传递给另外一个函数或者对象,最后再返回新的函数对象,而这个新的函数或者对象内部既实现了原函数的功能,也为其附加了新的功能。

 在实现目的-->为其他函数添加附加功能,在这个前提下还需要遵循两个原则,即:

    一、不修改被修饰函数的源代码。

    二、不修改被修饰函数的调用方式。

  其语法是:

    装饰器以 “@”开头,在定义的函数的上一行调用即加上“@xxx”,xxx为装饰器的函数名,来为这个函数来装饰附加功能。例如:

#装饰器deco
def deco1(func):
    pass
def deco2(func):
    pass    

@deco1  #@+装饰器的函数名,写在被装饰函数的上一行
@deco2  #一个被修饰函数可以有多个装饰器
#被修饰函数test
def test():
    pass

 

二、为什么要使用装饰器?

  我们可以通过下面这个例子可以很清晰的了解到装饰器的作用:

#假如你的老板给了你这样的一段代码,让你计算其运行的时长。

import time
def test():
    time.sleep(1)
    print("hello world")

#1、当然最直接的方式就是篡改源代码,例如:
import time
def test():
    start_time =time.time()
    time.sleep(1)
    print("hello world")
    end_time =time.time()
    print("costed time-->%s",%(end_time-start_time))

#2、随后老板说了:“这是咱们公司的核心代码,不能修改原代码”,随后你可能会想到高阶函数来实现,将原函数作为参数传入另外一个函数来实现:
import time
def test():
    time.sleep(1)
    print("hello world")

def deco(func):
    start_time =time.time()
    func()
    end_time = time.time()
    print("costed time-->%s"%(end_time-start_time)
#调用
deco(test)


#3、当你将这段代码交给老板时,老板又说:“目前这段代码以及投入使用了,怎么能随便修改调用方式呢?”这时候你又苦恼了,这时候你又想到了高阶函数中的将函数作为返回值
import time
def test():
    time.sleep(1)
    print("hello world")

def deco(func):
    start_time =time.time()
    func()
    end_time = time.time()
    print("costed time-->%s"%(end_time-start_time)
    return func
#调用
test=deco(test)
test()


#4、这时候你又会发现,原函数执行了两次,这时候老板又不满意了,“卧槽,这原函数怎么执行了两次啊”,于是又让你改,这时候你看到隔壁老王在写装饰器,你一下子惊为天人,于是有了下面这段代码:
import time
def test():
    time.sleep(1)
    print("hello world")

def deco(func):
    def wrapper(func):
        start_time =time.time()
        func()
        end_time =time.time()
        print("costed time-->%s"%(end_time-start_time)
    return wrapper

test = deco(test)
test()


#其实这时候deco函数就是装饰器的最原始从状态。用装饰器来实现就是这样的。
import time
#装饰器deco
def deco(func):
    def wrapper(func):
        start_time =time.time()
        func()
        end_time =time.time()
        print("costed time-->%s"%(end_time-start_time)
    return wrapper
#被修饰函数
@deco  #@deco <==> test =deco(test)
def test():
    time.sleep(1)
    print("hello world")
#调用
deco()
为什么需要装饰器

  从上面这个例子中可以看出,使用装饰器可以在不修改被修饰函数源代码以及不改变被修饰函数的调用方式的前提下,为函数添加新的附加功能。

 

三、如何来实现装饰器?

  其实在实现装饰器之前,我们需要了解 高阶函数、函数的嵌套和闭包等概念。当然这些我会在其他的文章中介绍。

  接下来我们学习如何实现装饰器。上述我们已经实现了Python装饰器的基本用法,接下来我们来了解 带参数的被修饰函数以及有返回值的被修饰函数如何实现装饰器。

  

  示例:

#1、装饰器的基本实现
import time
def timmer(func):
    def warpper(): #为了避免函数运行两次而需要的中间函数
        start_time= time.time()
        func()
        end_time =time.time()
        print("cost time--->:",end_time-start_time)
    return warpper

@timmer #@timmer <-->  test=timmer(test)
def test():
    time.sleep(1)
    print("in the test.")

test() #由于test=timmer(test),而执行timmer得到的返回值为wrapper;故其实调用test函数,本质上调用的是timmer下的子函数warpper。

#2、若被修饰函数带有返回值
import time
def timmer(func):
    def warpper(): #为了避免函数运行两次而需要的中间函数
        start_time= time.time()
        res=func()
        end_time =time.time()
        print("cost time--->:",end_time-start_time)
        return res
    return warpper

@timmer #@timmer <-->  test=timmer(test)
def test():
    time.sleep(1)
    print("in the test.")
    return "This is test' result"

test() #由于调用test()本质是执行wrapper(),故执行test()的返回值即为wrapper()的返回值即可。而需要的是被修饰函数为返回值,故把res作为wrapper的返回值即可。

#3、如被修饰函数带参数
import time
def timmer(func):
    def warpper(*args,**kwargs): #为了避免函数运行两次而需要的中间函数
        start_time= time.time()
        res=func(*args,**kwargs)
        end_time =time.time()
        print("cost time--->:",end_time-start_time)
        return res
    return warpper

@timmer #@timmer <-->  test=timmer(test)
def test(name):
    time.sleep(1)
    print("in the test.my name is %s."%name)
    return "This is test' result"

test(name)

 

  装饰器就先介绍到这里。这是重点哦。

 

posted @ 2018-05-30 20:03  Little_five  阅读(540)  评论(0编辑  收藏  举报