python装饰器(decorator)

所谓装饰器,就是一个函数,只不过它的操作对象是其他函数,是为帮某些函数添加功能而存在的,但在添加功能的时候有两个限制要求:

  1. 不能改变原函数的源码
  2. 不能改变原函数的调用方式

首先,在理解装饰器之前,我们需要了解一些概念

变量定义

与很多语言不同,python在定义变量时,不需要进行声明,直接赋值即可,如

a = 2
b = 2
print a,b
2 2
b = 3
print a,b
2 3

在进行“a = 2”的时候,相当于在内存中创建了一个“2”的对象,然后把对象“2”的地址赋给了 a ,如果这个时候,我们继续“b = 2“,python不会继续创建一个”2“对象,而是直接将”2“的地址赋给了 b ,且“2”这个对象的计数器加 1 (这牵涉到python内存管理的一些概念,就不加赘述),如果再继续”b = 3”则是又创建了一个“3”的对象,然后将地址赋给 b ,对 a 并没有改变。这样说有点乱,大家看图
变量定义

函数的定义

python中函数的定义利用关键字“def”:

def function():
    print "this is an function"

function()
this is an function

函数定义
是不是感觉函数的定义和变量定义十分相似,没错,其实定义一个函数与定义一个变量并没有什么很大的差别,函数名就相当于我们的变量名。大家都知道,变量可以作为参数传给函数,那么函数名是否也能作为参数传给其他函数呢?别着急,继续往下看。

函数名作为参数

def function1():
    print "this is an function1"
def function2(fuc):
    fuc()
    print "this is an function2"
function2(function1)

#运行结果
this is an function1
this is an function2

看到了没有,函数名是可以作为参数传递的,在上面的代码中,我们将“function1”作为参数传给了“function2”,在“function2”中,通过函数名调用“function1”,同样可以实现了“function1”的功能。
而对于“function2”我们是不是既实现了“function1”的功能,还实现了一些“function1”不具备的功能,是不是在没有修改“function1”源代码的基础上增加了某些功能,有没有,有没有,就说有没有!!!
那么这个是不是就是装饰器了,恭喜你,答错了!有很多眼尖的朋友肯定已经发现了,在开篇的两个要求中,只满足了“不修改函数源代码”这个一个要求;函数的调用方式已经改变了,之前是“function1()”,现在变成了“function2()”。这个要如何实现呢,后面就让我们来揭开装饰器的庐山真面目!!!

简单的decorator(装饰器)

def function1():
    print "this is an function1"
def decorat(func):
    def function2():
        func()
        print "this is an function2"
    return function2
function1 = decorat(function1)
function1()

#运行结果
this is an function1
this is an function2

在这段代码中,我们都做了些什么惊天动地的大事呢?一起来看看

  • 首先我们定义了一个简单函数“function1”
  • 然后又定义了一个“decorat”函数,这个函数带了一个参数“func”我们在“decorat”函数中又嵌套了一个“function2”函数,在“function2”的函数体中,我们调用了“func()”到这里,大家应该不难看出,之前传进来的参数“func”应该是一个函数名,调用结束后面,我们还添加一点其他的代码(你希望增加的其他功能),定义完“function2”,我们将“function2”这个函数名作为“decorat”的结果返回出去
  • 紧接着,我们通过“function1 = decorat(function1)”这条语句调用了“decorat”函数,是不是相当于将“function1”作为“func”传给了函数“decorat”,然后再将“decorat”的返回值赋给了“function1”
  • 最后调用“function1()”,这个时候,“function1”还是我们刚开始定义的那个“function1”吗?答案肯定不是,这个时候的“function1”已经被返回的“function2”替换,我们调用“function1()”的时候,就相当于调用了“function2()”
  • 就这样,我们在既没有修改原函数源代码以及调用方式的前提下,悄咪咪的增加了一些我们想给它添加的功能。是不是很神奇。

但按这种操作,每装饰一个函数,都需要“function1 = decorat(function1)”这样的一条语句,是不是很麻烦,不符合python简洁的风格,所以python提供了一个非常简便的方法:@decorat

def decorat(func):
    def function2():
        func()
        print "this function was decorated"
    return function2
@decorat
def function1():
    print "this is an function1"
@decorat
def function2():
    print "this is an function2"
function1()
function2()

#运行结果
this is an function1
this function was decorated
this is an function2
this function was decorated

只需要在每个你需要装饰的函数上面紧挨着加上一条“@decorat”语句,这个也叫语法糖,就像糖一样“粘”在函数的前面,这里的“decorat”是你自己的装饰器。也就是说“@decorat”等同于“function = decorat(function)”

被装饰的函数带参数

前面的被装饰函数都是不带参数的,属于最简单的形式,接下来,我们来看一下,如何装饰带参数的函数

def decorat(func):
    def function2(name):
        func(name)
        print "this function was decorated"
    return function2

@decorat
def function1(name):
    print "this is an function1"
    print "my name is "+name
@decorat
def function2(name):
    print "this is an function2"
    print "my name is " + name

function1("Tom")
function2("Alice")

#运行结果
this is an function1
my name is Tom
this function was decorated
this is an function2
my name is Alice
this function was decorated

在这个例子里面,大家不难看出,我给被装饰函数增加了一个“str”类型的参数,而它也成功被装饰了,这是怎么实现的呢?其实不难,细心的小伙伴可能已经发现了,只要我们在装饰器中内嵌的那个函数也含有同样的形参即可。但这样也造成了一个麻烦,无法实现无参函数的装饰,这里教大家一个小技巧,可变参数

def decorat(func):
    def function2(*args,**kwargs):
        func(*args,**kwargs)
        print "this function was decorated"
    return function2

@decorat
def function1(name):
    print "this is an function1"
    print "my name is "+name
@decorat
def function2():
    print "this is an function2"
    print "this function do not have name"

function1("Tom")
function2()

#运行结果
this is an function1
my name is Tom
this function was decorated
this is an function2
this function do not have name
this function was decorated

带参数的装饰器

前面说了一下如何装饰带参数的函数,那么可能有人会问,装饰器能不能也带参数呢?对某些函数区别的进行装饰,一个装饰器实现多个功能?答案是肯定的。话不多说,直接上例子,没有什么比代码更实在的。

import time
def decorat(mult):
    def wrapp(func):
        def function2(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            end_time = time.time()
            wast_time = end_time - start_time
            print mult,"倍的 wast_time =",wast_time*mult
            print "this function was decorated-------------------\n"
        return function2
    return wrapp

#如果我想实现计算function1的运行时间并打印
#以及打印function2的运行时间的两倍
@decorat(1)
def function1(name):
    print "this is an function1"
    time.sleep(3)
    print "my name is "+name
@decorat(2)
def function2():
    print "this is an function2"
    time.sleep(3)
    print "this function do not have name"

function1("Tom")
function2()

#运行结果
this is an function1
my name is Tom
1 倍的 wast_time = 3.0150001049
this function was decorated-------------------

this is an function2
this function do not have name
2 倍的 wast_time = 6.04199981689
this function was decorated-------------------

通过这个例子,大家可以看出,装饰器是可以带参数的;但带参数的装饰器需要多嵌套 1 重函数,用来接收你调用装饰器的时候传进来的参数,这段代码中的“wrapp”其实就相当于前面几次代码中的“decorat”,用来接收你的被装饰函数名,而这里的“decorat”则是用来接收你调用装饰器时传进来的参数。

装饰器的调用顺序

装饰器的调用顺序是和语法糖的书写顺序相反的

import time
def decorat2(func):
    def wrapp():
        func()
        print "this is decorat2"
    return wrapp

def decorat(mult):
    def wrapp(func):
        def function2(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            end_time = time.time()
            wast_time = end_time - start_time
            print mult,"倍的 wast_time =",wast_time*mult
            print "this function was decorated-------------------\n"
        return function2
    return wrapp

@decorat2
@decorat(2)
def function2():
    print "this is an function2"
    time.sleep(3)
    print "this function do not have name"

function2()

#运行结果
this is an function2
this function do not have name
2 倍的 wast_time = 6.00600004196
this function was decorated-------------------

this is decorat2
总结:这里简单叙述了一些装饰器概念和使用,我也刚学不久,如果有什么欠缺和不对的地方,欢迎大家指正,交流。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值