Python装饰器

2018-12-25  本文已影响0人  Yankee_13

献给莹莹

1.什么是装饰器

以下为装饰器例子

def w1(func):
    def inner():
        print('...验证权限...')
        func()
    return inner

@w1
def f1():
    print('f1 called')

@w1
def f2():
    print('f2 called')

f1()
f2()

该程序的输出为:

...验证权限...
f1 called
...验证权限...
f2 called

实际上python执行到@w1时,就已经开始装饰,相当于执行了:

f1=w1(f1)

2.两个装饰器的执行流程和装饰结果

def makeBold(fun):
    print('----a----')
    def inner():
        print('----1----')
        return '<b>' + fun() + '</b>'
    return inner

def makeItalic(fun):
    print('----b----')
    def inner():
        print('----2----')
        return '<i>' + fun() + '</i>'
    return inner

@makeBold
@makeItalic
def test():
    print('----c----')
    print('----3----')
    return 'hello python decorator'

ret = test()
print(ret)

输出结果:

----b----
----a----
----1----
----2----
----c----
----3----
<b><i>hello python decorator</i></b>
@makeItalic 等价于 test=makeItalic(test) 
@makeBold 等价于 test=makeBold(makeItalic.inner)

3.通用装饰器----对无参函数和有参函数进行装饰的区别

def w_say(fun):

    def inner(name):
        print('say inner called')
        fun(name)

    return inner

@w_say
def hello(name):
    print('hello ' + name)

只需要修改inner即可。
对于多个或不定长参数时,可以参考如下:

def w_add(func):
    def inner(*args, **kwargs):
        print('add inner called')
        func(*args, **kwargs)
    return inner

@w_add
def add(a, b):
    print('%d + %d = %d' % (a, b, a + b))

@w_add
def add2(a, b, c):
    print('%d + %d + %d = %d' % (a, b, c, a + b + c))

如果函数有返回值,在inner内返回即可

def w_test(func):
    def inner():
        print('w_test inner called start')
        str = func()
        print('w_test inner called end')
        return str
    return inner

@w_test
def test():
    print('this is test fun')
    return 'hello'

如果装饰器本身需要参数,可以这样写:

def func_args(pre=None):
    def w_test_log(func):
        def inner():
            print('...记录日志...visitor is %s' % pre)
            func()
        return inner
    return w_test_log

@func_args('yingying')
def test_log():
    print('this is test log')

即在外嵌套一层函数
至此,我们就可以引出通用的装饰器写法了

def w1(pre=None):
    def w1_test(func):
        def inner(*args,**kwargs):
            print("{} is now using the system".format(pre))
            ret=func(*args,**kwargs)
            return ret
        return inner
    return w1_test

@w1("icey")
def test_log(a,b,c,d=True):
    res = a + b
    if d:
        print(a+b+c)
    return res

以上程序输出结果

icey is now using the system
9

4.类装饰器

结合类的特性来说,类可以记录数据(属性),而函数不行(闭包某种意义上也可行),利用这种特性可以实现基于类的装饰器

1

class Test(object):
    def __init__(self, func):
        print('test init')
        print('func name is %s ' % func.__name__)
        self.__func = func

    def __call__(self, *args, **kwargs):
        print('装饰器中的功能')
        return self.__func()

@Test
def test():
    print('this is test func')

test()

输出结果为:

test init
func name is test 
装饰器中的功能
this is test func

2

class Counter:
    def __init__(self, func):
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        return self.func(*args, **kwargs)

@Counter
def foo():
    pass

for i in range(10):
    foo()

print(foo.count)

实际上相当于执行了foo=Counter(foo()),并执行了__call__内的内容。

参考资料:https://blog.csdn.net/u010358168/article/details/77773199

上一篇下一篇

猜你喜欢

热点阅读