Python自学之路——装饰器的秘密

先不管装饰器到底是个什么东东,让我们来聊一聊函数的几个点吧。我们知道,在python里,一切皆是对象,那么函数呢,当然也是对象,而且人家还是一级对象呐。既然是对象,那它就可以被赋值给变量,反之,通过变量也能调用函数。好,需特别注意的点来了,函数调用一定是函数名 + (),如果没有这个括号,函数是不会被调用的,它只能是表示内存里的一个地址,看下面

1 def happy():
2     print('be happy')
3 print (happy) #并没有调用happy函数,只是打印了happy的地址
4 happy() #调用happy函数
<function happy at 0x0000014B53C1F048>
be happy

我们再来看一下函数作为变量被赋值的例子

对于happy函数,如果我想在be happy这句前加个名字,该怎么办呢?理所当然的,我们会这样加

1 def happy():
2     print('mumu')
3     print('be happy')

可是,我们有没有想过,这样的话我们就破环了原来happy这个函数,并且,如果需要修改的函数量大一点,难不成我们还得一个个进去改吗?这种场景肯定是不允许的,于是,我们又琢磨出了一种方法……

1 def happy():
2     print('be happy')
3 def name(func):
4     print('mumu')
5     return func
6 happy = name(happy)
7 happy()
8 print(happy.__name__,name.__name__,)
mumu
be happy
happy name

有没有发现,上面代码中最神奇的一句就是 happy = name(happy) ,通过这句话,python将happy的地址传给了name函数,让name函数执行它的代码(即增加一个名字)然后返回happy的地址,最后调用happy。这样,我们在没有改变happy函数的前提下实现了需求,是不是很厉害呢?其实,这就是装饰器的秘密!

然而,人家既然是装饰器,肯定不会是这样和别的代码一样样的啊,看好了,人家的形式可是这样的呢 @+函数名     让我们看一下用了真正装饰器的代码长什么样吧

1 def name(func):
2     print('mumu')
3     return func
4 @name
5 def happy():
6     print('be happy')
7 happy()
8 print(happy.__name__,name.__name__,)

千万不要以为装饰器是如此简单噢,上一个稍微难一点的例子吧,借这个例子让我们好好捋一下装饰器在python解释器的原理

我们再来看一下下面两个程序的区别

 

写到这里,是不是发现我们都还没有参数的装饰器呢,给函数加个参数让我们来看看

def name(func):
    def inner(arg):
        print('mumu')
        return  func(arg)
    return inner
@name
def happy(user):
    print('%s be happy'% user)
    return "ye!"
ret = happy('must')
print('返回值:',ret)
mumu
must be happy
返回值: ye!

例子只是简单给了一个参数,如果你想要多个参数,甚至是多个不同类的参数,就用万能参数*args,**kwargs呗

现在我们应该明白,其实装饰器就是在原函数外面套了一层函数,使我们在调用原函数的时候调用的是装饰器返回给你的函数,那么,我们就想了,装饰器可以多个吗,一个一个地往函数上套?答案是肯定的,就看一下两个装饰器的例子吧,其实我觉得的吧,多个装饰器没必要,搞得那么复杂……

 

 1 def outer1(func):
 2     def inner():
 3         print ('o1,before')
 4         func()
 5         print ('o1,after')
 6     return inner
 7 
 8 def outer2(func):
 9     def inner():
10         print ('o2,before')
11         func()
12         print ('o2,after')
13     return inner
14 
15 @outer2
16 @outer1
17 def happy():
18     print ('happy everyday')
19 
20 happy()

 

o2,before
o1,before
happy everyday
o1,after
o2,after

对于这种多个装饰器我们可以理解为它像俄罗斯套娃一样,最里面的原始函数被外面的装饰器函数一层一层地嵌套,原始函数的函数名传递给最靠近它的装饰器,里层的装饰器返回值会传递给外层装饰器的参数。

 

 

 

posted @ 2016-08-26 14:44  木木dan子  阅读(147)  评论(0编辑  收藏  举报