装饰器

1. 什么是装饰器

装饰器(Decorators)是修改其它函数功能的函数

2. 理解装饰器的基础知识

(1)函数中可以定义函数

def fun():
    def inner():
        print("This is a inner function!")
    inner()

(2)函数可以返回一个函数对象

def fun():
    def inner():
        print("This is a inner function!")
    return inner

(3)函数可以作为参数传递给函数

def fun(func_para):
    print(func_para())

3. 装饰器例子

(1)首先定义一个装饰器decorator(),它是个函数,主要功能是函数参数接收一个函数对象a_func,然后定义内部函数wrapTheFunction()对函数对象a_func修饰(增加功能),然后将内部函数返回。

def decorator(a_func):
    def wrapTheFunction:
        print("您好!")
        a_func()
        print("谢谢!")
    return wrapTheFunction

(2)定义一个待修饰的函数

def func():
    print("我是函数func()")

(3)使用装饰器decorator()修饰func()

>>>func()
我是函数func()
>>>decor_func=decorator(func)
>>>decor_func()
您好!
我是函数func()
谢谢!

可以看到,我们对函数func()使用装饰器后,在函数本身没有改动的情况下,增加了输出“您好!”“谢谢!”的功能,这就是装饰器dcorator()的作用。

4. @符号的用法

为了避免像上面代码那样使用装饰器时生成额外的函数变量decor_func,使用装饰器的方法是使用@符号声明在被修饰函数的定义之前。

@decorator
def func():
    print("我是函数func()")

之后调用的func()都是装饰器decorator()修饰过的。

>>>func()
您好!
我是函数func()
谢谢!

5. 完整的装饰器写法

上述代码虽然实现了对函数func()的修饰,但是上述写法会改变func()的函数名称和注释文档。

>>>func.__name__
>>>wrapTheFunction

这显然不是我们想要的,因此完整的装饰器写法如下:

from functools import wraps
# 定义装饰器
def decorator(a_func):
    @wraps(a_func)
    def wrapTheFunction():
        print("您好!")
        a_func()
        print("谢谢!")
    return wrapTheFunction
# 使用装饰器
@decorator
def func():
    print("我是函数func()")

调用后的输出为

>>>func()
您好!
我是函数func()
谢谢!
>>>func.__name__
func

可以看到函数名称不会发生改变!

6. 装饰器模板

from functools import wraps
def decorator_name(f):
    @wraps(f)
    def decorated(*args,**kwargs):
        if not can_run:
           return "Function will not run"
        return f(*args,**kwargs)
    return decorated

7. 装饰器应用——日志

创建日志装饰器,在函数调用时,会将函数名称写入到日志文件中。

from functools import wraps
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrap_function(*args,*kwargs):
            log_string=func.__name__+" was called"
            print(log_string)
            with open(logfile,'a') as log_f:
                 log_f.write(log_string+'\n')
            return func(*args,**kwargs)
        return wrap_function
    return logging_decorator

可以看到,在logging_decorator()的外部又增加了一层函数logit(),这是为了传入日志文件名称logfile这个参数,这样的结果是装饰器可以携带参数。

@logit('my_log.log')
def myfunc():
    pass

8. 装饰器类——以日志为例

定义一个装饰器类,实现函数调用时将函数名称写入日志文件,发送邮件等复杂功能。

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)
              # 日志写入文件
              with open(logfile,'a') as log_f:
                   log_f.write(log_string+'\n')
              # 发送邮件
              self.notify()
              return func(*args,**kwargs)
          return wrapped_function
      def notify(self):
          # 发送邮件
          pass

使用装饰器:

@logit('my_log.log')
def myfunc():
    pass
posted @ 2022-01-12 18:56  帅气无敌朋子  阅读(70)  评论(0编辑  收藏  举报