码迷,mamicode.com
首页 > 编程语言 > 详细

Python基础(装饰器)

时间:2015-11-24 06:32:10      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:python

代码的编写和软件的开发,都应该遵循开放封闭原则。

开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。其核心思想是:

对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。

对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

而装饰器(就是函数)的作用就是为已经存在的对象添加额外的功能。


此篇文章主要介绍装饰器的五种使用情况。

需求场景:

让一个已经开发完成的功能在执行之前,先执行某些操作。


一、基本用法

原函数:

def func1():

    print ‘old func1‘

func1()

执行结果:

old func1


定义装饰器:

def w1(func):    #这里参数func的值就是被装饰的函数的函数名

    def _w1():   #定义一个新的函数

        print ‘Begin new func %s()‘%func.func_name  #装饰器中新加入的操作

        func()  #执行完新加入操作后开始执行原函数

    return _w1   #返回被重新装饰过的函数,函数名为_w1 


使用装饰器装饰原函数:

@w1        #装饰器用法,@+装饰器函数名,放在需要被装饰的函数上面

def func1():   

    print ‘old func1‘

func1()

执行结果:

Begin new func func1()

old func1


二、动态参数,可以装饰带有N个(N>=0)参数的函数

def w2(func):

    def _w2(*args,**kwargs):    #可接受任意参数的函数

        print ‘Begin new func %s()‘%func.func_name

        func(*args,**kwargs)

    return _w2 


@w2

def func1():        #不带参数的函数

    print ‘old func1‘

@w2

def func2(*args,**kwargs): #带任意参数的参数

    print ‘old func2,arg is %s‘%args


func1()    #执行不带参数的函数

func2(‘test‘) #执行带参数的函数,并赋值一个test参数

执行结果:

Begin new func func1()

old func1

Begin new func func2()

old func2,arg is test


三、被装饰的函数带有return值

错误写法:

def w3(func):

    def _w3(*args,**kwargs):

        print ‘Begin new func %s()‘%func.func_name

        func(*args,**kwargs)

    return _w3

@w3

def func3(*args,**kwargs):

    print ‘old func3,arg is %s‘%args

    return ‘done‘    #定义函数的返回值为done


re = func3(‘test‘)    #获取函数的返回值

print re        #打印函数的返回值

执行结果:

Begin new func func3()

old func3,arg is test

None    #结果函数的返回值为None


正确写法:

def w3(func):

    def _w3(*args,**kwargs):

        print ‘Begin new func %s()‘%func.func_name

        return func(*args,**kwargs)

    return _w3

@w3

def func3(*args,**kwargs):

    print ‘old func3,arg is %s‘%args

    return ‘done‘


re = func3(‘test‘)

print re

执行结果:

Begin new func func3()

old func3,arg is test

done    #得到正确的返回值,请自行查看两种写法的差别。


四、多个装饰器装饰同一个函数(多个装饰器的情况下,从里往外(下往上)装饰,装饰完成后,从外往里(上往下)执行)

应用场景:同一个函数希望扩展两个完全不一样的功能,比如一个验证功能,一个记录日志的功能。


用一个例子进行说明:

def first(func):    #装饰器1

    print ‘%s() was post to first()‘%func.func_name

    def _first(*args,**kw):

        print ‘Call the function %s() in _first().‘%func.func_name

        return func(*args,**kw)

    return _first


def second(func):    #装饰器2

    print ‘%s() was post to second()‘%func.func_name

    def _second(*args,**kw):

        print ‘Call the function %s() in _second().‘%func.func_name

        return func(*args,**kw)

    return _second


@first     #装饰器1

@second    #装饰器2

def test(*args,**kwargs):

    print ‘test() args -->‘,args

test(‘123‘)

执行结果:

test() was post to second()

_second() was post to first()

Call the function _second() in _first().

Call the function test() in _second().

test() args --> (‘123‘,)


逐条解释:

test() was post to second()     #由于装饰器second在test函数上面,所以会先用装饰器second装饰test,这时候装饰器second的参数是test,执行后的返回值是_second函数,里面的func变量值是test函数

_second() was post to first()   #由于_second函数上还有一个装饰器first,所以会用装饰器first装饰_second,这时候装饰器first的参数是_second, 执行后的返回值是_first函数,里面的func变量值是_second函数

Call the function _second() in _first().    #所有装饰器装饰完成,开始执行,这里会先执行_first函数,等于在里面执行_second()

Call the function test() in _second().  #开始执行_second函数,等于在里面执行test()

test() args --> (‘123‘,)   #test函数执行的结果


五、多层装饰器,(带参数的装饰器、不要和第二种情况搞混)

应用场景:当希望使用装饰器装饰函数时,装饰器内部调用的方法是可定义的,比如装饰A函数时,内部调用AA方法,装饰B函数时,内部调用BB方法。


用一个例子进行说明:

def Before(request,kargs):

    print ‘before -->‘,request


def After(request,kargs):

    print ‘after <--‘,kargs


def Filter(before_func,after_func):    #第一层装饰器

    def outer(main_func):    #第二层装饰器

        def wrapper(request,kargs):  #第二层装饰器定义的函数  


            before_result = before_func(request,kargs)

            if(before_result != None):

                return before_result;


            main_result = main_func(request,kargs)

            if(main_result != None):

                return main_result;


            after_result = after_func(request,kargs)

            if(after_result != None):

                return after_result;


        return wrapper    #第二层装饰器返回的函数

    return outer    #第一层装饰器返回的函数,也就是另一个装饰器


@Filter(Before, After)

def Index(request,kargs):

    print ‘index‘

Index(‘begin‘,‘end‘)

执行结果:

before --> begin

index

after <-- end

执行过程:

1、解释器读取到装饰器@Filter(Before, After),开始执行Filter(Before, After)函数

2、进入Filter函数执行,并传入参数‘Before, After‘,此时Filter函数中参数before_func=Before,参数after_func=After。

 继续往下执行,函数中定义了一个outer函数,由于未调用该函数,所以不执行该函数,继续往下执行

3、Filter函数return了outer函数作为本次执行的返回值

4、根据Filter函数执行的返回值创建了新的装饰器@outer

5、开始执行outer函数,此时其参数main_func的值为原函数Index,也就是main_func=Index

6、outer函数中定义了另一个函数wrapper,其参数的值是原函数Index传入的参数值,由于未调用该函数,所以不执行该函数,继续往下执行

7、outer函数return了wrapper函数作为本次执行的返回值

8、原函数Index被重新赋值等于wrapper函数,也就是Index=wrapper

9、开始执行新的Index函数(即wrapper函数)也就是wrapper(‘begin‘,‘end‘)

10、执行时会先执行before_func(request,kargs),也就是Before(‘begin‘,‘end‘)

11、再执行main_func(request,kargs),也就是Index(‘begin‘,‘end‘)

12、最后执行after_func(request,kargs),也就是After(‘begin‘,‘end‘)

执行完成。

本文出自 “一行菜鸟上青天” 博客,请务必保留此出处http://rmeos.blog.51cto.com/761575/1716097

Python基础(装饰器)

标签:python

原文地址:http://rmeos.blog.51cto.com/761575/1716097

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!