函数装饰器

2020-05-11  本文已影响0人  蝉时雨丶

不带参数的装饰器

>>> import time
>>> def timer(func):
      def deco():
        start=time.time()
        func()
        stop=time.time()
        print(stop-start)
      return deco
>>> def test():
    time.sleep(2)
    print("test is running!")

>>> test=timer(test)
>>> test()
test is running!
2.002716302871704

等价于

>>> import time
>>> def timer(func):
    def deco():
        start=time.time()
        func()
        stop=time.time()
        print(stop-start)
    return deco

>>> @timer
def test():
    time.sleep(2)
    print("test is running!")
>>> test()
test is running!
2.025238513946533

对带参数函数进行装饰

def w_say(fun):
    """
    如果原函数有参数,那闭包函数必须保持参数个数一致,并且将参数传递给原方法
    """

    def inner(name):
        """
        如果被装饰的函数有行参,那么闭包函数必须有参数
        :param name:
        :return:
        """
        print('say inner called')
        fun(name)

    return inner

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


hello('wangcai')

输出结果为

say inner called
hello wangcai

具体说明代码注释已经有了,就不再单独说明了。
此时,也许你就会问了,那是一个参数的,如果多个或者不定长参数呢,该如何处理呢?看看下面的代码你就秒懂了。

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))
add(2, 4)
add2(2, 4, 6)

输出结果为:

add inner called
2 + 4 = 6
add inner called
2 + 4 + 6 = 12

对带有返回值的函数进行装饰

下面对有返回值的函数进行装饰,按照之前的写法,代码是这样的

def w_test(func):
    def inner():
        print('w_test inner called start')
        func()
        print('w_test inner called end')
    return inner
@w_test
def test():
    print('this is test fun')
    return 'hello'
ret = test()
print('ret value is %s' % ret)

输出结果为:

w_test inner called start
this is test fun
w_test inner called end
ret value is None

可以发现,此时,并没有输出test函数的‘hello’,而是None,那是为什么呢,可以发现,在inner函数中对test进行了调用,但是没有接受不了返回值,也没有进行返回,那么默认就是None了,知道了原因,那么来修改一下代码:

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'
ret = test()
print('ret value is %s' % ret)

输出结果:

w_test inner called start
this is test fun
w_test inner called end
ret value is hello

带参数的装饰器

def func_args(pre='xiaoqiang'):
    def w_test_log(func):
        def inner():
            print('...记录日志...visitor is %s' % pre)
            func()
        return inner
    return w_test_log
# 带有参数的装饰器能够起到在运行时,有不同的功能
# 先执行func_args('wangcai'),返回w_test_log函数的引用
# @w_test_log
# 使用@w_test_log对test_log进行装饰
@func_args('wangcai')
def test_log():
    print('this is test log')
test_log()

输出结果为:
...记录日志...visitor is wangcai
this is test log

简单理解,带参数的装饰器就是在原闭包的基础上又加了一层闭包,通过外层函数func_args的返回值w_test_log就看出来了,具体执行流程在注释里已经说明了。
好处就是可以在运行时,针对不同的参数做不同的应用功能处理。

上一篇下一篇

猜你喜欢

热点阅读