zoukankan      html  css  js  c++  java
  • python 语法之 装饰器decorator

    装饰器 decorator

    或者称为包装器,是对函数的一种包装。

    它能使函数的功能得到扩充,而同时不用修改函数本身的代码。

    它能够增加函数执行前、执行后的行为,而不需对调用函数的代码做任何改变。

    下面用一个简单的例子介绍装饰器:

    1 # 函数hello,输出 hello + name 的字符串 
    2 def hello(name):
    3     return 'hello ' + name    

    下面,我们希望在每一个调用 hello 函数的时候,将输出的字符串用 <tag>包住

    比如:hello john 变成 <tag>hello john<tag>

    方法1:自定义wrapper 函数

    1 def wrapper(tag, func, *arg, **kvargs):
    2     tag = "<" + tag + ">"              #根据参数生成 <tag>
    3     return tag + func(*arg, **kvargs) + tag  #将<tag>加在func结果的首末
    4 
    5 if __name__ == "__main__":
    6     wrapper('p', hello, 'john')              #输出: <p>hello john<p>   

    这种方法成功修改了函数 hello 的行为,不过需要修改对 hello的调用。

    每一个调用hello 的地方,都要给成调用wrapper,并修改参数列表

    方法2:自定义decorator 函数

    为了不改变对 hello的调用。我们需要得到一个新的函数对象,它修改 hello的行为,并用这个对象对 hello赋值。

    从而调用 hello的时候,调用的是扩充行为后的 hello

     1 def myDecorator(func, tag)
     2     def myWrapper(*arg, **kvargs):   #重新包装func,其参数列表与func一致
     3         sign = "<" + tag + ">"
     4         return sign + func(*arg, **kvargs) + sign
     5     return wrapper2            #调用 myDecorator 能返回一个函数对象,用于给func重新赋值
     6 
     7 hello = myDecorator(hello, "div")    #用新的函数对象修改hello
     8 
     9 if __name__ == "__main__":
    10     hello("john")        #输出 <div>hello john<div>

    这样,只要hello被myDecorator 赋值一次,以后再调用hello 时,就调用的是包装后的函数

    方式3:python的 decorator

    python 的装饰器所做的事与方式2类似

    它通过语法糖使装饰器看起来更清晰、简介,而不用每次都书写方式2中第7行代码 hello = myDecorator(hello, "div")

     1 def setTag(tag):        #由于此装饰器需要参数,所以要再套一层
     2     def myDecorator(func):    #装饰器的核心,接受函数对象做参数,返回包装后的函数对象
     3         def myWrapper(*arg, **kvargs):    #包装的具体过程
     4             sign = "<" + tag + ">"
     5             return sign + func(*arg, **kvargs) + sign
     6         return myWrapper
     7     return myDecorator
     8 
     9 @setTag("div")    #用@标签在定义函数时套上装饰器
    10 def hello(name):
    11     return 'hello' + name    

    本质上,方式2 与 方式3 完成的是同一件事,只不过方式3 比方式2 代码更简洁,方便。

    比如,现在要给 hello 函数套上三个标签<body><div><p>

    如果用方式2

    hello = myDecorator(myDecorator(myDecorator(hello, "body"),"div"),"p")

    如果用方式3

    @myDecorator("body")
    @myDecorator("div")
    @myDecorator("p")
    def hello(name)
        return 'hello' + name

    在多个装饰器嵌套的情况下,python内置的decorator 结构更清晰。

    装饰器语法总结

    完成一个装饰器需要两步:1.定义装饰器函数 2.在被装饰的函数定义之前加上 @装饰器

    下面的伪代码展示了这个过程

     1  def myDecorator(...):    #定义装饰器,可能带参数
     2      def decorator(func):    #装饰器核心,以被装饰的函数对象为参数,返回装饰后的函数对象
     3          def wrapper(*args, **kvargs):    #装饰的过程,参数列表适应不同参数的函数
     4              ...    #修改函数调用前的行为
     5              func(*args, **kvargs)    #调用函数
     6              ...    #修改函数调用后的行为
     7          return wrapper
     8      return decorator
     9  
    10 @myDecorator(...):    #给函数加上装饰器
    11 def myFunc(...):      #自己定义的功能函数
    12     ...

    参考:

    [1] The Code Ship 中关于python装饰器的说明:http://thecodeship.com/patterns/guide-to-python-function-decorators/

    [2] python 装饰器的主要用途与例子:https://wiki.python.org/moin/PythonDecoratorLibrary

  • 相关阅读:
    Junit单元测试
    win7的6个网络命令
    WOJ1024 (POJ1985+POJ2631) Exploration 树/BFS
    WOJ1022 Competition of Programming 贪心 WOJ1023 Division dp
    woj1019 Curriculum Schedule 输入输出 woj1020 Adjacent Difference 排序
    woj1018(HDU4384)KING KONG 循环群
    woj1016 cherry blossom woj1017 Billiard ball 几何
    woj1013 Barcelet 字符串 woj1014 Doraemon's Flashlight 几何
    woj1012 Thingk and Count DP好题
    woj1010 alternate sum 数学 woj1011 Finding Teamates 数学
  • 原文地址:https://www.cnblogs.com/yutongzhu/p/5615764.html
Copyright © 2011-2022 走看看