廖雪峰老师的decorator教程练习:同一decorator @log,既可以使用@log().又可以使用@log(参数),没搞懂

练习一

请编写一个decorator,能在函数调用的前后打印出'begin call''end call'的日志。

这部分并不难,在wrapper中将函数的运行值赋值给一个变量,再返回该变量即可,如下:

import functools
def log(fn):
    @fuctools.wraps(fn)
    def wrapper(*args,**kw):
        print ('begin call')
        x=fn(*args,**kw)
        print('begin call')
        return x
    return wrapper

 练习二

再思考一下能否写出一个@log的decorator,使它既支持:

@log
def f():
    pass

又支持:

@log('execute')
def f():
    pass

 这个练习的关键点在于要使得log在有参数和无参数的情况下都有对应的执行,这一点在C++中是可以通过重载函数解决的,但是在python中还没接触到,所以没能想出来

参考答案如下:

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('Begin call')
            print('calling func: %s' % func.__name__)   
            r = func(*args, **kw)
            print('Eng call')
            return r
        return wrapper
    return decorator if isinstance(text, str) else decorator(text)

 这里最关键的一步是为不同的输入选择合适的执行方式。

引用下廖雪峰老师原文最精彩的部分:

@log放到now()函数的定义处,相当于执行了语句:

now = log(now)

和两层嵌套的decorator相比,3层嵌套的效果是这样的:

>>> now = log('execute')(now)

我们需要做的就是理解并将它们用条件判断表示出来!

log()函数输入的是字符串,就切换为就是带参数的装饰器)

如果log()函数输入的不是字符串,就切换为不带参数的装饰器。(当然这里没有考虑其他情况,实际使用时还应进行拓展)

 但是这个参考答案带来一个疑问:decorator仅有一个定义即decorator(func),那么最后return的 decorator情况下,字符串难道可以作为函数来执行decorator定义中的语句?

不过也有收获:get了 return A if xxx else return B的操作

猜你喜欢

转载自blog.csdn.net/Zeke_Leeeee/article/details/87875579