• 关于Python的装饰器(1)


    Python的装饰器的概念,一直有点微妙。之前在StackOverflow上看过一篇感觉说明的很清楚的介绍:

    *A decorator must accept a function as an argument
     
    参考地址:
     
    Objects are data with methods attached, closures are functions with data attached.
     
    英文水平有限,对于这句话我的理解一直是这样:
     1 def a(fn):
     2     print "function a"
     3     def tmpfun(*args):
     4         print "tmpfunc"
     5         fu(*args)
     6     return tmpfun
     7 
     8 @a
     9 def b(*args):
    10     print "function b" + str(args)
    此时,调用b(1, 2)等效于a(b(1, 2)),编译器解析代码时,会先执行b,然后执行a。
    今天遇到有人问类似的问题,试着写了一下,发现等效方法运行出错。
    经过实验,发现用装饰器修饰的b函数调用时,b(1, 2)等效于a(b)(1, 2)。
    装饰器函数需要的参数应该是被修饰的函数对象,而不是被修饰函数对象的执行结果。
    以下为验证代码:
     1 def addSpan(fn):
     2     print "addSpan executed"
     3     def n(*args):
     4         print "spam, spam, spam"
     5         return fn(*args)
     6     return n
     7 
     8 @addSpan
     9 def useful(a, b):
    10     print a**2 + b**2
    11 
    12 def synonym(a, b):
    13     print a**2 + b**2
    14 
    15 if __name__ == '__main__':
    16     useful(3, 4)
    17     addSpan(synonym)(3, 4)

    执行结果为:

    addSpan executed
    spam, spam, spam
    25
    addSpan executed
    spam, spam, spam
    25
    [Finished in 0.1s]

    可以看出虽然形式上被修饰的函数会先被执行,但是实际执行时,仍然是以装饰器函数为入口开始执行的。

    反思:

    作为装饰器的函数必须接收参数,而且必须返回可执行的函数对象,否则将出错:

    def a():
        print "function a"
    
    @a
    def b():
        print "function b"
    
    b()

    运行结果:

    Traceback (most recent call last):
      File "/Users/.../decorator_test1.py", line 18, in <module>
        @a
    TypeError: a() takes no arguments (1 given)
    [Finished in 0.1s with exit code 1]

    如果装饰器函数声明了参数,但是没有声明返回对象,或者声明的返回对象是不可被调用的对象,同样会出错:

    def a(fn):
        print "function a"    // 没有声明返回对象
    
    @a
    def b():
        print "function b"
    
    b()

    执行结果:

    Traceback (most recent call last):
      File "/Users/.../decorator_test1.py", line 27, in <module>
    function a
        b()
    TypeError: 'NoneType' object is not callable
    [Finished in 0.1s with exit code 1]

    可以看到后续动作将None作为返回对象继续执行,然后出错。

    或者:

    def a(fn):
        print "function a"
        return "asd"    // 声明返回对象为不可被调用的类型
    
    @a
    def b():
        print "function b"
    
    b()

    运行结果:

    function a
    Traceback (most recent call last):
      File "/Users/.../decorator_test1.py", line 28, in <module>
        b()
    TypeError: 'str' object is not callable
    [Finished in 0.1s with exit code 1]

     正常运行结果:

    def a(fn):
        print "function a"
        return fn    // 返回参数获得的函数对象
    
    @a
    def b():
        print "function b"
    
    b()

    运行结果:

    function a
    function b
    [Finished in 0.1s]

    关于装饰器还有一些疑问,将在第二篇进行验证。

  • 相关阅读:
    C#中List<T>用法
    windows phone中,将crash report记录下来,写入文件,方便分析
    解决问题之,wp项目中使用MatchCollection正则表达式匹配出错
    提问的智慧
    toolkit,phonetextbox中实现用户按回车键会换行
    Hibernate主键生成策略
    hibernate.cfg.xml位置及JDBC配置
    Java与数字签名
    MyEclipse不能编译的一种解决方法
    java读文件和写文件编码方式的控制
  • 原文地址:https://www.cnblogs.com/harelion/p/5730081.html
Copyright © 2020-2023  润新知