代码改变世界

IronPython0.9.3发布了 —— 介绍一下Decorator

2005-10-17 15:44  FantasySoft  阅读(2358)  评论(12编辑  收藏  举报

        上周五就已经从IronPython Team发出的Mail中得知IronPython又发布了新版本——0.9.3。慵懒的周末让偶怠慢了跟踪报道,真不好意思了。不过也正好有了时间来酝酿一下这篇Post该写些什么,而不致于空洞无物。
        在短短的不到一个月的时间里就发布了新的版本,改动果然如我猜想的那样并不是很大,主要是集中在修复与Closure相关的bugs。大家从
IronPython的Workspace中可以看到Release Notes并且下载到最新的版本。虽然这次的改动并不算太大,而且与我最近关注的Python特性也没有太大关系,但是一个看得见的小改进让我开心不已——Decorator的bug修复了,几个原来无法正确运行的程序总算让我看到了期待的运行结果!0.9.2中实现的Decorator给我的感觉就像是半成品,让我没了兴趣。而新版本中的Decorators总算焕然一新,让我精神为之振奋,而Decorator也顺理成章地成为了这篇Post的主角。
        Decorator是Python2.4中引入的新特性,它的原意是为了能够实现一般OO语言中的static方法或者说是类方法。然而在实际应用当中,
它的应用范围则是非常广。为了了解Decorator,我们先来看一段简单的代码:

第一部分:
>>>
 def decorate(func):
     print func.func_name

>>>
 @decorate
 def test():     
     print 
"test function"

          #以上代码等价于 decorate(test)
test

>>>test()   # test这个function在全局范围不可见
Traceback (most recent call last):
   at 
<shell>

AttributeError: 
'NoneType' object has no attribute '__call__'

------------------------------------------------
第二部分:
>>> def decorate(source, dest):
     print source, dest
     def wrapper(func):
         pass
     
return
 wrapper

>>> @decorate("source""dest"
)
 def test():
     print 
"test function"

          #以上代码等价于 decorate(
"source""dest")(test)
source dest

从以上代码可以看出Decorator本身就是一个function,它在语法上的定义跟一般function是没有区别的;Decorator在使用时通过@来表示;被Decorator修饰的实体是function对象。虽然Decorator在语法上与一般的function并无二致,但是其定义的内容和参数则是有考究的。我把Decorator看作是一个可以接受function对象为参数的特殊function,Decorator在定义的时候是必须带参数的。Decorator在使用的时候有两种方式,带参数和不带参数。使用方式不同也决定了Decorator在定义上的不同。当Decorator在使用的时候不带参数,那么其定义就有且仅有一个参数,这个参数所对应的实参就是被修饰的function,如以上代码第一部分所示;当Decorator在使用的时候带参数的话,那么其定义所包含的参数个数与使用时是一致。在这种情况下,Decorator定义的限制就比较多了,它必须包含function,并且要将该function作为Decorator的返回值,如以上代码中第二部分所示。被Decorator修饰的function就像是匿名函数一样,虽然有function名,却无法通过function名调用到该function。因此,以上的示例代码是没有什么实际意义的,只是为了方便说明问题。
        一个真正有实际作用的Decorator通常都是对传入的function对象进行处理后并返回或者创建一个新的function对象并返回。不管怎样一个有用的Decorator都会返回一个function对象,这样才能在使用了Decorator之后可以调用到一个修饰后的function。具体的可以参考limodou所写的decorator的使用一文中decorator函数的定义部分。
        回头再看看自己写的东西,似乎越说越复杂了,其实Decorator是一个很简单的概念,它只不
过是一个可以修改function的function罢了。以下是不使用Decorator与使用Decorator来实现相同效果的代码,大家可以从中看到Decorator只是一个简单概念的演化而已。


>>> def test():
     pass

>>>
 def decorate(func):
     func.author 
= "FantasySoft"

     
return func

>>>
 decorate(test)
<function test at 0x000000000000002F>

>>> test.author
'FantasySoft'

-------------------------------------------  
>>> def decorate(func):
     func.author 
= "FantasySoft"

     
return func

>>>
 @decorate
 def test():
     pass

>>>
 test.author
'FantasySoft'

        把修改其他function的function独立出来,作用并不是那么的明显。但是这样做可以将一些公共模块归类为Decorator,使得代码组织更为清晰。而在多层函数调用的情况下,使用Decorator的语法也会显得简单明了。其他的Motivation,大家可以参考Decorators for Functions and Methods(PEP 318) 。