Python装饰器的个人小理解

个人对Python的装饰器小理解

标签: Python 装饰器 设计模式


刚刚开始学Python的时候看的廖雪峰先生的学习笔记,囫囵吞枣看了一遍就撸起袖子开干了,对Python很多特殊功能的理解其实并没有多深入。相信很多人也是一样,只是为了使用Python的某个库而入坑,而没有深入的学习Python这门语言。那么就让我们从装饰器开始,由浅入深吧。

什么是装饰器?

装饰器我将它理解为在不修改函数内部的前提下,对函数的一个“强化”。装饰器的使用其实一开始我还是挺懵逼的,后来慢慢开始理解到闭包、函数对象之后,对装饰器又有了新的理解,原来装饰器能做的事情还是很多的。那么我们就一步步的去理解到底什么是装饰器吧。

闭包的概念

大家都知道,在函数式编程中,函数内部就是一个作用域,更底层的讲,一个函数被调用时,它的内存空间其实只在进程内存空间的一个栈中。当函数调用完成返回时,操作系统就会回收这个栈,所以函数内部的所有变量的生存期只存在于这个函数被调用的时候。

在Python中,函数是可以嵌套定义的,比如说:

def outer(value):
    def inner():
        value = 10
        print value
    inner()
    return value

ans = outer(20)
print ans

运行得到的结果:

10
20

而在Python中,一切皆为对象,因此函数也能够作为对象被返回,进而被调用。举个栗子:

def outer():
    def inner():
        print "I'm inner!!!"
    return inner
    
obj = outer()
obj()

运行得到的结果:

I'm inner!!!

那么如果这个返回的函数内部使用了作用域仅在outer()函数中的变量,按理说这样调用inner()是会出错的。但是在Python中的闭包特性,令这一“违反常理”的操作可执行:

def outer(value):
    def inner():
        print "value is "%value
    return inner
    
obj_fun = outer(0) #照理说value在这次函数调用后就应该被释放了
obj_fun()

运行得到的结果:

outer_value is 0

在这里,函数inner()就是一个闭包,这个“包”里不仅仅装了函数的逻辑,也装了函数运行所需要的数据(或者说对象)。到目前来看,闭包好像还是没什么卵用,但是你想想,如果我们的参数不是一个“value”,而是一个“function”,那会怎么样?比如说:

def outer(func, value):
    def inner():
        print "run parameter of function before."
        func(value)
        print "run parameter of function after."

    return inner


def speak(value):
    print "+%ds "%(value)

new_speak = outer(speak, 1)
new_speak()

运行结果为:

run parameter of function before.
+1s
run parameter of function after.

装饰器

可能有的同学到现在还不理解到底闭包能干什么,那好我们现在设想一个情景:

之前在我们的网站中,某一个URI对于所有外来的的get请求都可以返回一句“苟利国家生死以”,但是现在觉得有些人不是同道中人,需要对这些请求加一些验证,只有请求头中包含Agent : real fans字段的用户才能收到这句话。

如果要在处理请求的函数里直接修改,那函数显然会越来越臃肿,让之后的人看着蛋疼,这时候装饰器就大派用场了:

from server import handler  #handler is a function
from Request import get_request
from log import log_input

new_request = get_request()

def wrapper(func, request):
    def checker():
        if not request.header.CheckHeader({"Agent":"real fans"}):
            log_input("this guy is not hasi")
            return None
        else:
            log_input("real fans!")
            return func(request)
    return checker
        
new_handler = wrapper(handler, new_request)
new_handler()

这样,在完全不修改函数handler()的前提下,解决了这个问题。如果之后要扩大福利,不需要验证,那样也不需要对代码进行多少修改就能达到效果。什么?你还觉得太麻烦?!幸好程序员的懒惰就是业界进步的阶梯,Python为了让大家能更早的收工,增加了一个对装饰器的语法糖:

def outer(func):
    def inner(value):
        print "run parameter of function before."
        func(value)
        print "run parameter of function after."

    return inner

@outer
def speak(value):
    print "+%ds "%(value)

speak(1)

运行结果为:

run parameter of function before.
+1s
run parameter of function after.

是不是更简单了呢。

以上是个人粗浅的一点认识,之后有更深入了解会及时回来更新的

2017.7.3

posted @ 2017-07-03 00:46  Fucky  阅读(317)  评论(0编辑  收藏  举报