python函数装饰器

1.1 python装饰器

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短。

python的装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。

1.2 python装饰器应用场景

比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。 

1.3 装饰器语法糖

python提供了@符号作为装饰器的语法糖,使我们更方便的应用装饰函数。但使用语法糖要求装饰函数必须return一个函数对象。因此我们将上面的func函数使用内嵌函数包裹并return。

1.3.1 函数装饰器

(1)不带参数装饰器,不带参数函数

def use_logging(func):
  def _deco():
    print("%s is running" % func.__name__)
    func()
  return _deco
@use_logging
def bar():
  print('i am bar')
if __name__ == '__main__':
    bar()

装饰器相当于执行了装饰函数use_loggin后又返回被装饰函数bar,因此bar()被调用的时候相当于执行了两个函数。等价于use_logging(bar)()。

执行结果:

bar is running
i am ba

(2)不带参数装饰器,带参数函数

def use_logging(func):
  def _deco(a, b):
    print("%s is running" % func.__name__)
    func(a, b)
  return _deco
@use_logging
def bar(a, b):
  print('i am bar:%s'%(a+b))
if __name__ == '__main__':
    bar(1, 2)

 参数需要传入两个参数并计算值,因此我们需要对内层函数进行改动传入我们的两个参数a和b,等价于use_logging(bar)(1,2)

输出结果:

 bar is running
i am bar:3

(3)不带参数装饰器,带不定参数函数

def use_logging(func):
  def _deco(*args, **kwargs):
    print("%s is running" % func.__name__)
    func(*args, **kwargs)
  return _deco
@use_logging
def bar(a, b):
  print('i am bar:%s'%(a+b))
@use_logging
def foo(a, b, c):
  print('i am bar:%s'%(a+b+c))
if __name__ == '__main__':
    bar(1, 2)
    foo(1, 2, 3)

输出结果:

bar is running
i am bar:3
foo is running
i am bar:6

(4)带参数装饰器,带参数函数

def use_logging(level):
  def _deco(func):
    def __deco(*args, **kwargs):
      if level == "warn":
        print "%s is running" % func.__name__
      return func(*args, **kwargs)
    return __deco
  return _deco
@use_logging(level="warn")
def bar(a,b):
  print('i am bar:%s'%(a+b))
bar(1,3)

 等价于use_logging(level="warn")(bar)(1,3)

(5)使用functools.wraps

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表

def use_logging(func):
  def _deco(*args,**kwargs):
    print("%s is running" % func.__name__)
    func(*args,**kwargs)
  return _deco
@use_logging
def bar():
  print('i am bar')
  print(bar.__name__)
bar()

输出结果:

#bar is running

#i am bar

#_deco

函数名变为_deco而不是bar,即装饰器装饰完之后,我们被装饰的函数的名字会变成装饰器函数。

增加@functools.wraps(f), 可以保持当前装饰器去装饰的函数的 __name__的值不变

import functools
def use_logging(func):
  @functools.wraps(func)
  def _deco(*args,**kwargs):
    print("%s is running" % func.__name__)
    func(*args,**kwargs)
  return _deco
@use_logging
def bar():
  print('i am bar')
  print(bar.__name__)
bar()

 1.3.2 类装饰器

class loging(object):
  def __init__(self,level="warn"):
    self.level = level
  def __call__(self,func):
    @functools.wraps(func)
    def _deco(*args, **kwargs):
      if self.level == "warn":
        self.notify(func)
      return func(*args, **kwargs)
    return _deco
  def notify(self,func):
    # logit只打日志,不做别的
    print "%s is running" % func.__name__
@loging(level="warn")#执行__call__方法
def bar(a,b):
  print('i

继承类装饰器

class email_loging(Loging):
  '''
  一个loging的实现版本,可以在函数调用时发送email给管理员
  '''
  def __init__(self, email='[email protected]', *args, **kwargs):
    self.email = email
    super(email_loging, self).__init__(*args, **kwargs)
  def notify(self,func):
    # 发送一封email到self.email
    print "%s is running" % func.__name__
    print "sending email to %s" %self.email
@email_loging(level="warn")
def bar(a,b):
  print('i am bar:%s'%(a+b))
bar(1,3)

参考文献:

【1】Python 函数装饰器 | 菜鸟教程

【2】如何理解Python装饰器? - 知乎 

【3】Python装饰器用法实例总结 - arvin_feng - 博客园

你可能感兴趣的:(自动化测试,python)