您的位置:首页 > 编程语言 > Python开发

Python系列之 - 装饰器

2018-03-20 16:57 218 查看
装饰器主要是用来对函数的操作,我们把定义的函数比作一个蛋糕的话,那么装饰器就是盒子,如果要吃蛋糕就先打开盒子。具体到程序中就是在函数外层又套了一层,套的那一层就是一个装饰器。这么说可能有点抽象,那么我们下面就来举例说明.1 应用场景需求假设我们有一个程序,里面有N个函数(模块),由于是新上的功能,为了打开市场领导要求所有的功能免费开放,不加任何限制。[python] view plain copydef func1():  
    print("模块1")  
  
def func2():  
    print("模块2")  
func1()  
func2()  
如上,两个功能模块没有任何限制,谁都可以用。那么现在有问题了,系统上线一段时间之后,公司决定部分限制免费, 部分功能模块需要会员才能访问,其中包括func1,必须登录验证完后才能使用。这个时候我们怎么做呢,我们可能会这么做:[python] view plain copydef log_auth(user,passwd):  
    # 登录验证模块  
    if user == "aa" and passwd == "bbb":  
        # 执行验证代码..........  
        pass  
    return True  
  
def func1():  
    if log_auth("aaa","1234"):  
        print("模块1")  
  
def func2():  
    print("模块2")  

增加一个验证模块,然后在需要验证的模块中增加一个判断,如果验证成功就执行模块。不错,这样做确实可以实现,但是这样做是合理的吗,这样我们就修改了原有的已经上线的代码,这是开发的大忌。那么我们怎么能够实现不动原有代码,又增加这个功能呢。我们知道函数是可以传递参数的,我们能不能定义一个函数比如outer,将func1这个函数作为一个参数传递进去,直接执行outer就可以在里面增加权限判断后调用函数func1呢。看一下下面代码:[python] view plain copydef outer(func):  
    # 验证模块  
    print("验证")  
    func()  
  
def func1():  
    print("模块1")  
  
outer(func1)    
以上代码执行后即进行了验证,有执行了原有的函数fuc1,而且原有func1也没有变更。貌似解决了我们的问题,你一定很开心问题解决了。但你想一想问题真的解决了吗?程序其它地方以前是调用的func1()函数,那我们所有调用这个函数的地方还是调用原函数,要实现必须验证的话原有调用func1的地方是不都需要改为outer(func1)了呢,这样还是改动了原有程序。你可能会想,那就把原来的func1函数的地址指向outer(func1)不就可以了吗,于是你改成了这样[python] view plain copydef outer(func):  
    # 验证模块  
    print("验证")  
    func()  
  
def func1():  
    print("模块1")  
  
func1 = outer(func1)  
func1  
哈哈,问题解决! 可是你发现了一个问题, outer(func1)就执行了,你如果把这个赋给func1,其它地方调用的时候都是用func1()来执行的,这样就有问题了。这个时候不知道怎么办了吧。我们看一个例子:[python] view plain copydef func1():  
    print("模块1")  
  
print(func1)  
结果:<function func1 at 0x00000000037381E0>  
我们看到在函数执行时,单func1只是内存中的一个地址,只有执行 func1() 才是执行函数,那么回到上面的问题。 现在 outer(func1)就已经是函数了,你要想使用func1 = auth(func1) ,是不是只要把auth(func1)的结果变成一个内存地址就可以了呢? 也就是将它变成一个函数名,那就得加上def。 基于这一点,我们把上面的改造一下。看下面的代码:[python] view plain copydef auth(func):  
    def outer():  
        # 验证模块  
        print("验证")  
        func()  
    return outer  
  
  
def func1():  
    print("模块1")  
  
  
func1 = auth(func1)  
func1()  

我们把outer()封装在auth()函数里面,让func1 = auth(func1),这样auth(func1)函数执行后返回了一个结果,这个结果就是outer,这个只是个函数名,在内存中只是一个地址。这样func1 = outer的内存地址, 当我们再执行func1()的时候,是不是就相当于是执行了outer()函数。而这个函数就是我们要的东西,这样是不是就实现了我们所要的功能呢。这样一来真个程序就完美了。哈哈.....可以收工了!!!!!!!等一下,还有个小问题,如果我们真这么搞得话,是不是每个需要增加验证功能的函数都重新赋值一下:func = auth(func) ???如果我们有200个函数都需要增加验证功能,那是不是要写200个这样的赋值,这样也太麻烦了吧,是不是太low了,有没有更好的办法呢?? 答案是当然有,你能想到这个问题,我们的python开发者难道想不到吗? 我们看这个代码:[python] view plain copydef auth(func):  
    def outer():  
        # 验证模块  
        print("验证")  
        func()  
    return outer  
 
@auth  
def func1():  
    print("模块1")  
  
  
func1()  
看到了吗,我们只需要在要增加验证的函数上使用@函数名就OK了,这样一来,原来的函数func1没有任何变化,也没有改变其它地方调用func1的调用方式,还增加了验证功能,是不是perfect ???说了一大堆,我们不是要讲装饰器吗? 难不成这就是装饰器?? 你说对了,这就是装饰器!那你会问了,如果我的func1还有参数怎么搞???好问题!!看一下下面的代码:[python] view plain copydef auth(func):  
    def outer(para):  
        # 验证模块  
        print("验证")  
        func(para)  
    return outer  
 
@auth  
def func1(args):  
    print("模块1,我的参数:%s " %args)  
  
  
func1("参数来了")  

是不是搞定了,很easy了吧。以上就是装饰器的实现。下面给一个多参数,多层装饰器的例子,原理一样[python] view plain copydef log_auth(bef, end):  
    def outer(func):  
        def inter(**arg):  
            print("login  successful")  
            r1 = bef(arg["before"])  
            r2 = end(arg["end"])  
            a = func(arg["middle"])  
            result1 = "{before},{middle},{end}".format(before=r1, middle=a, end=r2)  
            return result1  
        return inter  
    return outer  
  
def before(arg1):  
    return "before:{0}".format(arg1)  
  
def later(arg2):  
    return "later:{0}".format(arg2)  
 
@log_auth(before, later)  
def index_page(arg):  
    return "Index {0}".format(arg)  
  
  
print(index_page(before="1111", middle="2222", end="3333"))  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: