zoukankan      html  css  js  c++  java
  • python闭包以及装饰器

     

    
    

    一 闭包

      什么是闭包
        封装了数据和函数的函数,其实就是两个函数的嵌套

      闭包有什么作用
        具有数据和功能,内存开销比对象小,做装饰器

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

    
    

      闭包和函数的区别:

        闭包:在闭包中,既有函数,又有数据,而且数据是闭包里面独有的数据,与外界无影响;

        函数:函数中,需要使用的全局变量,在一定程度上是受到限制的,因为全局变量不仅仅是一个函数使用,其他的函数也可能会使用到,

           一旦修改会影响到其他函数使用全局变量,所以全局变量不能随便修改从而在函数的使用中受到一定局限性。

      代码如下:

      def text(k,b):
        def text1(x):
          print(k*x + b)
        return text1    
      t = text(1,2)
      t(2)
    一 装饰器是什么
      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='admin@myproject.com', *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)

     



  • 相关阅读:
    ASP.NET Web API 2.0 统一响应格式
    [翻译]ASP.NET Web API 2 中的全局错误处理
    【WPF】UserControl 的 Load事件
    解决MS SQL Server 使用HashBytes函数乱码问题
    实例化MD5CryptoServiceProvider报错:此实现不是 Windows 平台 FIPS 验证的加密算法的一部分
    添加扩展方法,提示编译错误 “缺少编译器要求的成员”
    [调试]VS2013调试时提示“运行时当前拒绝计算表达式的值”
    jquery chosen 插件多选初始化
    Asp.net WebForm 中无法引用App_Code文件夹下的类
    文本非法字符过滤 简体转换繁体
  • 原文地址:https://www.cnblogs.com/wangxiongbing/p/10123400.html
Copyright © 2011-2022 走看看