从应用角度理解python中的装饰器

装饰器:
python的函数定义可以被多个装饰器修饰
表示方式是:

decorated ::= decorators (classdef | funcdef)
decorators ::= decorator+
decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
dotted_name ::= identifier ("." identifier)*

装饰器的表达式在函数被定义时计算,和函数定义在同一个定义域。
装饰器表达式的结果必须有返回值,返回值将成为参数被外层装饰器当参数使用。
多个装饰器是嵌套工作的。
官网上给出的代码如下:

@f1(arg)
@f2
def func():
    pass
#等价于
def func():
    pass
func = f1(arg)(f2(func))

个人的理解是,装饰器起的作用和增加函数差不多,但是可以使逻辑更清晰,代码结构更优化。
比如,我需要通过一种方法,对每一个函数开始调用和调用结束时都输出一条信息,初步解决办法就是在每写一个函数,开头结尾都调用一下print,这也是我之前写print风格的调试代码最常用的习惯,现在有了装饰器这个东西就很好办了:

def printlog(func):
    def wrapper():
        print 'Start of Calling function: ', func.__name__
        func()
        print 'End of Calling function: ', func.__name__
    return wrapper

@printlog
def helloFunc():
    print 'We are in helloFunc'
    print 'do some complex things'

helloFunc()

在这段代码里,主要程序helloFunc中只有两行代码,表示该函数主体部分,而print的工作被封装在外面了,这样不仅使主要程序逻辑更清晰,而且也实现了printlog的代码重用,即可以给各个函数都增加这个装饰器,通过python内省(?)的机制,识别每个不同的函数。
简单的思考可以发现,装饰器有一个最强大的功能就是参数验证。很多时候,我们要在一个函数开头写很多if-else语句,去验证参数的合法性(是否在某一范围,类型转换什么的),这样导致的后果就是以至于找不到实现该函数主要功能的代码了。同时在看这段代码如何实现的时候,参数验证也是直接跳过的,就像读OS内核时老师告诉我们的一样,不要关注太多OS内核中的分支条件,以免陷进去看不到主要的精髓。
然后,现在有了装饰器,参数验证这种意义重大又很干扰可读性的工作就跑到函数外面去了。

def validate(argofdec):
    def handleFunc(func):
        def handle(arg):
            if arg>argofdec:
                func(arg)
            else:
                print 'ERROR: x <',argofdec
        return handle
    return handleFunc

@validate(3)
def foo(x):
    print 'foo: x is ', x

foo(2)  #output: ERROR: x < 3
foo(5)  #output: foo: x is  5

总结,装饰器函数的参数是要装饰的方法,要返回一个函数,一般可以直接是输入的函数

———-
这好像属于面向切面编程…概念很晦涩,我暂时也不想懂…
好久不更了,准备近期连着把我几个草稿都发了,这是第一发。

Tags : ,

One thought on “从应用角度理解python中的装饰器”

  1. 赞,decorator一直都没太想到平时可以用的地方。
    面向切面就是把负责一个方面的代码放在一起,比如负责检查输入写一块儿,记录日志的写一块儿,缓存的写一块。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Click the right image To submit your comment: