当前位置:   article > 正文

【Pyhont笔记】装饰器总结_def logging_decorator(func)

def logging_decorator(func)

知识点:python中函数也是对象,可以传递和当做参数的。

装饰器可看成是一个复杂语法的缩写:

@a

def b

       ...

等价于

b=a(b)

 

1.最基本的装饰器:参数为函数,返回函数的函数,可作为修饰器

  1. def decorator(in_func):#函数做参数
  2. def out_func(a,b,c):
  3. print("输出点啥")
  4. return in_func(a,b,c)
  5. return out_func#返回函数,参数需要与被装饰函数(use_func)参数一致,或者用*args,**kwargs
  6. #使用
  7. @decorator
  8. def use_func(a,b,c):
  9. ...
  10. #等价于
  11. use_func=decorator(use_func)

问题1:名称信息丢失

  1. print(use_func.__name__)#被装饰函数名称
  2. # Output: wrapTheFunction

解决方法:

  1. from functools import wraps
  2. def decorator(in_func):
  3. @wraps(in_func)
  4. ...
  5. return out_func#返回函数
  6. print(use_func.__name__)#被装饰函数名称
  7. # Output: use_func

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

 

问题2:use_func的参数如何获得的

use_func的参数是如何获得的:

我们可以在定义 out_func 函数的时候指定参数:
  1. def out_func(a,b,c):
  2. logging.warn("%s is running" % in_func.__name__)
  3. return in_func(a,b,c)
  4. return out_func

这样 use_func 函数定义的参数就可以定义在 out_func函数中。use_func如果有很多个参数。当装饰器不知道 use_func 到底有多少个参数时,我们可以用 *args 来代替:

  1. def out_func(*args):
  2. logging.warn("%s is running" % in_func.__name__)
  3. return in_func(*args)
  4. return out_func

对于use_func 函数还定义了的关键字参数比如:

  1. def use_func(name, age=None, height=None):
  2. ...

这时,可以把 out_func 函数指定关键字函数:

  1. def out_func(*args, **kwargs):
  2. # args是一个数组,kwargs一个字典
  3. logging.warn("%s is running" % in_func.__name__)
  4. return in_func(*args, **kwargs)
  5. return out_func

 

2.带参数的装饰器:

例1:

装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,该装饰器接收唯一的参数就是执行业务的函数 use_func 。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。比如,我们可以在装饰器中指定日志的等级,因为不同业务函数可能需要的日志级别是不一样的。

  1. def use_logging(level):
  2. def decorator(in_func):
  3. def out_func(*args, **kwargs):
  4. if level == "warn":
  5. logging.warn("%s is running" % in_func.__name__)
  6. elif level == "info":
  7. logging.info("%s is running" % in_func.__name__)
  8. return in_func(*args)
  9. return out_func
  10. return decorator
  11. @use_logging(level="warn")
  12. def foo(name='foo'):
  13. print("i am %s" % name)
  14. foo()

上面的 use_logging 是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level="warn")调用的时候,Python 能够发现这一层的封装,并把参数传递到装饰器的环境中

@use_logging(level="warn")等价于@decorator

例2:

  1. from functools import wraps
  2. def logit(logfile='out.log'):
  3. def logging_decorator(func):
  4. @wraps(func)
  5. def wrapped_function(*args, **kwargs):
  6. log_string = func.__name__ + " was called"
  7. print(log_string)
  8. # 打开logfile,并写入内容
  9. with open(logfile, 'a') as opened_file:
  10. # 现在将日志打到指定的logfile
  11. opened_file.write(log_string + '\n')
  12. return func(*args, **kwargs)
  13. return wrapped_function
  14. return logging_decorator
  15. @logit()
  16. def myfunc1():
  17. pass
  18. myfunc1()
  19. # Output: myfunc1 was called
  20. # 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
  21. @logit(logfile='func2.log')
  22. def myfunc2():
  23. pass
  24. myfunc2()
  25. # Output: myfunc2 was called
  26. # 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串

3.装饰器类:

装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

  1. from functools import wraps
  2. class logit(object):
  3. def __init__(self, logfile='out.log'):
  4. self.logfile = logfile
  5. def __call__(self, func):
  6. @wraps(func)
  7. def wrapped_function(*args, **kwargs):
  8. log_string = func.__name__ + " was called"
  9. print(log_string)
  10. # 打开logfile并写入
  11. with open(self.logfile, 'a') as opened_file:
  12. # 现在将日志打到指定的文件
  13. opened_file.write(log_string + '\n')
  14. # 现在,发送一个通知
  15. self.notify()
  16. return func(*args, **kwargs)
  17. return wrapped_function
  18. def notify(self):
  19. # logit只打日志,不做别的
  20. pass

这个实现有一个附加优势,在于比嵌套函数的方式更加整洁,而且包裹一个函数还是使用跟以前一样的语法:

  1. @logit()
  2. def myfunc1():
  3. pass

现在,我们给 logit 创建子类,来添加 email 的功能(虽然 email 这个话题不会在这里展开)。

  1. class email_logit(logit):
  2. '''
  3. 一个logit的实现版本,可以在函数调用时发送email给管理员
  4. '''
  5. def __init__(self, email='admin@myproject.com', *args, **kwargs):
  6. self.email = email
  7. super(email_logit, self).__init__(*args, **kwargs)
  8. def notify(self):
  9. # 发送一封email到self.email
  10. # 这里就不做实现了
  11. pass

从现在起,@email_logit 将会和 @logit 产生同样的效果,但是在打日志的基础上,还会多发送一封邮件给管理员。

参考自:

1:https://www.runoob.com/w3cnote/python-func-decorators.html\

2:https://foofish.net/python-decorator.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/317153
推荐阅读
相关标签
  

闽ICP备14008679号