美文网首页
Python装饰器

Python装饰器

作者: Ovie | 来源:发表于2017-01-16 23:51 被阅读0次

    以前在IMOOC上学习的笔记。今晚整理下发出来。

    要理解装饰器,先了解函数作用域和闭包。

    1. 函数作用域的查找顺序概括为:L -> E -> G -> B

      local 函数内部作用域

      enclosing 函数内部与内嵌函数之间

      global 全局作用域

      build-in 内置作用域

    2. 闭包(Closure)就是内部函数中对enclosing作用域的变量进行引用。举例:

      # -*-coding:utf-8 -*-
      
      def foo(func):
         def wrapper(x, y):
             if isinstance(x, int) and isinstance(y, int):
                 return func(x, y)
             else:
                 print 'Error'
                 return None
         return wrapper
      
      def mysum(x, y):
          return x + y
      
      def mymul(x, y):
          return x * y
      
      mysum_ex = foo(mysum)
      print mysum_ex(1, 2)
      print mysum_ex.__closure__
      
      mymul_ex = foo(mymul)
      print mymul_ex(1, 2)
      print mymul_ex.__closure__
      

    执行完foo函数,内部变量被回收,这里是func变量。但是在执行mysum_ex函数时,为什么访问得到func变量呢?因为闭包函数mysum_ex(实际上就是wrapper函数)有一个属性__closure__,存储着需要用到的enclosing 变量,即func变量。

    闭包作用:封装和代码复用。怎么体现?

    上面的mysum用来执行两个整数的加法,mymul用来执行两个整数的乘法。如果直接执行mysum('1', 2)mymul('1', 2)是会报错:TypeError: cannot concatenate 'str' and 'int' objects。所以需要添加判断参数是否是int类型的逻辑代码,如mysum函数

     def mysum(x, y):
         if isinstance(x, int) and isinstance(y, int):
             return x + y
         else:
             print 'Error'
             return None
    

    mymul函数也需要相同的判断逻辑,所以利用闭包把这部分判断逻辑代码封装到wrapper()中,通过传递函数对象funcwrapper()函数内部使用,来决定到底使用加法操作还是乘法操作。这部分判断参数是否是int类型的逻辑代码达到了代码复用。

    最后说装饰器。上面的闭包例子用装饰器来写:

    # -*-coding:utf-8 -*-
    import functools
    
    def foo(func):
        @functools.wraps(func)
        def wrapper(x, y):
            if isinstance(x, int) and isinstance(y, int):
                return func(x, y)
            else:
                print 'Error'
                return None
        return wrapper
    
    
    @foo
    def mysum(x, y):
        return x + y
    
    print mysum(1, 2)
    print mysum('1', 2)
    

    执行结果:

    3
    Error
    None
    

    对于装饰器的几点说明:

    1. 装饰器是对闭包的使用。

    2. 传递一个函数对象func给装饰器foofoo返回一个新的函数对象。对于闭包,就不一定要传递函数对象,可以传递其它类型的对象。如:

      # -*-coding:utf-8 -*-
      
      def set_passline(passline):
          def cmp(val):
              if val >= passline:
                  print "pass"
              else:
                  print "failed"
          return cmp
      
      f_100 = set_passline(60)
      print f_100.__closure__
      f_100(89)
      

      传递的是整数对象。

    3. def mysum(x, y):上边加@foo,是Python提供的语法。表示mysum这个函数对象作为func参数传递给foo(func)函数,再把foo函数返回的新函数对象赋给mysum

    4. 建议给装饰器里的wrapper加上@functools.wraps(func)装饰器。不加的时候mysum.__name__的值是wrapper,加上去值才是mysum

    相关文章

      网友评论

          本文标题:Python装饰器

          本文链接:https://www.haomeiwen.com/subject/lwtmbttx.html