闭包 装饰器

一 闭包

  只发生在函数的嵌套中,一个内层函数调用了外层函数的"变量"
  nonlocal 不是本地作用域的
  检测是否为闭包的内置属性 __closure__
  闭包函数可以保留其用到的变量的引用
  外层函数的返回值就是内层函数的引用

def text(k,b):
  k = 1
  b = 2
  def text1(x):
    x = 3
    print(k*x + b)
  return text1    
t = text()
print(t)
一 装饰器是什么
  python的装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。
  它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
  概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
  
  1 模板装饰器
def wrapper(func):
      def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        return result
      return inner
    @wrapper   # text=wrapper(text)
    def text():
      print("python")

  2 多个装饰器装饰同一个函数

def wrapper(func):
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return "<p>" + ret + "</p>"
    return inner

def decorate(func):
    def inner(*args, **kwargs):
        ret = func(*args, **kwargs)
        return "<h1>" + ret + "</h1>"
    return inner

@wrapper
@decorate
def show():
    return " ++love python++ "

ret = show()
print(ret)

result : "<p><h1> ++love python++ </h1></p>"

  3 装饰器带参数

def set_lever(lever_num):
    def wrapper(func):
        def inner(*args, **kwargs):
            if lever_num == 1:
                print("已经获得1的权限")
            elif lever_num == 2:
                print("已经获得2的权限")
            ret = func(*args, **kwargs)
            return ret
        return inner
    return wrapper

@set_lever("first")
def text1():
    # print("ha111")
    return "love python111"

@set_lever("second")
def text2():
    print("ha222")
    return "love python222"
print(text1)

  4 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解决这个问题。

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

 
 

  @use_logging
  def bar():
  print('i am bar')
  print(bar.__name__)

  bar()

 
 

  #result:
  #bar is running
  #i am bar
  #bar ,这个结果是我们想要的。OK啦!

 

  5 带参数和不带参数的装饰器

 
 

import functools

 
 

def use_logging(arg):
  if callable(arg):#判断参入的参数是否是函数,不带参数的装饰器调用这个分支
  @functools.wraps(arg)
    def _deco(*args,**kwargs):
      print("%s is running" % arg.__name__)
      return arg(*args,**kwargs)
    return _deco
  else:#带参数的装饰器调用这个分支
  def _deco(func):
  @functools.wraps(func)
    def __deco(*args, **kwargs):
      if arg == "warn":
        print "warn%s is running" % func.__name__
        return func(*args, **kwargs)
    return __deco
  return _deco

 
 


@use_logging("warn")
# @use_logging
def bar():
print('i am bar')
print(bar.__name__)

 
 

bar()

 

三 类装饰器

  1 普通类装饰器

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 am bar:%s'%(a+b))

bar(1,3)

  2 继承类装饰器

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)


猜你喜欢

转载自www.cnblogs.com/wangxiongbing/p/10123400.html