装饰器

装饰器?

  • 什么是装饰器?

装饰器本质上是一个 Python 函数,它可以让其函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器常用场景有:插入日志、授权、计算脚本运行时间、事务处理、缓存等。

  • 加了装饰器后函数是怎么运行的?
def new_deco(func):
    def wrapped_func(*args,**kwargs):
        print("before executing func")
        func(*args,**kwargs)
        print("after executing func")
    return wrapped


@new_deco
def test_func():
    print("start to executing func")


test_func()
print("the test_func name is:{}".format(test_func.__name__))

# Outputs:
# "before executing func"
# "start to executing func"
# "after executing func"
# "the test_func name is:wrapped_func"

test_func 函数的函数名被 wrapped_func。它重写了我们函数的名字和注释文档(docstring)

from functools import wraps


def new_deco(func):
    @wraps(func)
    def wrapped(*args,**kwargs):
        print("before executing func")
        func(*args,**kwargs)
        print("after executing func")
    return wrapped


@new_deco
def test_func():
    print("start to executing func")


test_func()
print("the test_func name is:{}".format(test_func.__name__))

# Outputs:
# "before executing func"
# "start to executing func"
# "after executing func"
# "the test_func name is:test_func"

@wraps 接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

  • 不带参数装饰器的示例
from functools import wraps

def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging
@logit
def addition_func(x):
   """Do some math."""
   return x + x

# Output: addition_func was called
  • 带参数的装饰器
    • 理解:在函数中嵌入装饰器
    • 示例:
from functools import wraps
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator

@logit()
def myfunc1():
    pass

myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串

@logit(logfile='func2.log')
def myfunc2():
    pass

myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
  • 类装饰器
    • 概念:类装饰器具有灵活度大、高内聚、封装性等优点。可依靠内部的 call 方法
    • 示例:
from functools import wraps


class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile

    def __call__(self, func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile并写入
            with open(self.logfile, 'a') as opened_file:
                # 现在将日志打到指定的文件
                opened_file.write(log_string + '\n')
            # 现在,发送一个通知
            self.notify()
            return func(*args, **kwargs)
        return wrapped_function

    def notify(self):
        # logit只打日志,不做别的
        pass


@logit()
def myfunc1():
    print("test")


myfunc1()
# Output:myfunc1 was called
#         test
  • 装饰器的执行顺序
@a
@b
@c
def f ():
a(b(c(f)))

参考资料:

https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/

https://www.zhihu.com/question/26930016

posted @ 2018-10-22 17:47  深圳-随风  阅读(137)  评论(0编辑  收藏  举报