美文网首页
装饰器与偏函数

装饰器与偏函数

作者: 5f2a6061653d | 来源:发表于2019-03-04 09:37 被阅读20次

    装饰器的概念

    在讲解装饰器之前,先看一段简单的程序,如下所示。

     1  def f2(func):
     2      def f1():
     3          x = func()
     4          return x + 1
     5      return f1
     6  def func():
     7      print('func()函数')
     8      return 1
     9  decorated = f2(func)
     10 print(decorated())
     11 print(func())
    

    运行结果如下图所示。

    运行结果
    在上例中, 第1行定义了一个带单个参数func的名称为 f2的函数,第2行f1()函数为闭包,其中调用了func()函数并将func()函数的返回值加1返回。这样每次f2()函数被调用时,func的值可能会不同,但不论func()代表何种函数,程序都将调用它。
    从程序运行结果可看出,调用函数decorated()的返回值为2,调用func()函数的返回值为1,两者都输出“func()函数”,此时称变量decorated是func的装饰版,即在func()函数的基础上增加新功能,上例是将func()函数的返回值加1。
    大家可以用装饰版来代替func,这样每次调用时就总能得到附带其他功能的 func 版本,如下所示。
     1  def f2(func):
     2      def f1():
     3          return func() + 1
     4      return f1
     5  def func():
     6      print('func()函数')
     7      return 1
     8  func = f2(func)
     9  print(func())
    

    运行结果如下图所示。


    运行结果

    在上述代码中,第3行等价于上例中第3、4行,第8行将上例中第9行decorated改为func,这样每次通过函数名func调用函数时,都将执行装饰的版本。
    通过上述代码可以得出装饰器的概念,即一个以函数作为参数并返回一个替换函数的可执行函数。装饰器的本质是一个嵌套函数,外层函数的参数是被修饰的函数,内层函数是一个闭包并在其中增加新功能。

    @符号的应用

    上例中使用变量名将装饰器函数与被装饰函数联系起来,此外,还可以通过@符号和装饰器名实现两者的联系,如下所示。

     1  def f2(func):
     2      def f1():
     3          return func() + 1
     4      return f1
     5  @f2
     6  def func():
     7      print('func()函数')
     8      return 1
     9  print(func())
    

    运行结果如下图所示。


    运行结果

    在上例中,第5行通过@符号和装饰器名实现装饰器函数与被装饰函数联系,第9行调用func()函数时,程序会自动调用装饰器函数的代码。

    装饰有参数的函数

    装饰器除了可以装饰无参数的函数外,还可以装饰有参数的函数,如下所示。

     1  def f2(func):
     2      def f1(a = 0, b = 0):
     3          return func(a, b) + 1
     4      return f1
     5  @f2
     6  def func(a = 0, b = 0):
     7      print('func()函数')
     8      return a + b
     9  print(func(6, 8))
    

    运行结果如下图所示。


    运行结果

    在上例中,第6行定义一个带有两个默认参数的func()函数,第5行将f2()函数声明为装饰器函数,用来修饰func()函数,第9行调用func装饰器函数,注意f1()函数中的参数必须包含对应func()函数的参数。

    带参数的装饰器

    通过上面的学习,装饰器本身也是一个函数,即装饰器本身也可以带参数,此时装饰器需要再多一层内嵌函数,如下所示。

     1  def f3(arg = '装饰器的参数'):
     2      def f2(func):
     3          def f1():
     4              print(arg)
     5              return func() + 1
     6          return f1
     7      return f2
     8  @f3('带参数的装饰器')
     9  def func():
     10     print('func()函数')
     11     return 1
     12 print(func())
    

    运行结果如下图所示。


    运行结果

    在上例中,第1行定义装饰器函数,其由三个函数嵌套而成,最外层函数有一个装饰器自带的参数,内层函数不变,相当于闭包的嵌套。第8行将f3()函数声明为装饰器函数,用来修饰func()函数。
    若读者不理解此代码,可以将装饰器写成如下代码,如下所示。

     1  def f3(arg = '装饰器的参数'):
     2      def f2(func):
     3          def f1():
     4              print(arg)
     5              return func() + 1
     6          return f1
     7      return f2
     8  def func():
     9      print('func()函数')
     10     return 1
     11 f2 = f3('带参数的装饰器')
     12 func = f2(func)
     13 print(func())
    

    运行结果如下图所示。


    运行结果

    在上例中,将装饰器分解成闭包的嵌套,这种写法更容易理解,此外,还可以将第11、12行代码写成如下代码:

    func = f3('带参数的装饰器')(func)
    

    上述代码相当于省略中间变量f2。

    偏函数

    函数最重要的一个功能的是复用代码,有时在复用已有函数时,可能需要固定其中的部分参数,除了可以通过默认值参数来实现之外,还可以使用偏函数,如下所示。

     1  def myAdd1(a, b, c):
     2      return a + b + c
     3  def myAdd2(a, b):
     4      return myAdd1(a, b, 123)
     5  print(myAdd2(1, 1))
    

    运行结果如下图所示。


    运行结果

    在上例中,第3行定义一个myAdd2()函数,与第1行myAdd1()函数的区别仅在于参数c固定为一个数字123,这时就可以使用偏函数的技术来复用上面的函数。

    相关文章

      网友评论

          本文标题:装饰器与偏函数

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