5 PEP 318函数和方法的修饰符

python 2.2 虽然通过添加静态方法和类方法扩展了python对象模型,却没有提供定义静态方法或类方法的新语法。你只能象通常方式那样写一个函数定义语句,然后将该函数作为参数传递给staticmethod()或classmethod()来将其封装成一个新类型的方法。你的代码看起来就象下面这样:

   1 class C:
   2    def meth (cls):
   3        ...
   4 
   5    meth = classmethod(meth)   # Rebind name to wrapped-up class method 将属性名重新绑定到封装后的类方法

如果这个方法定义很长的话,很容易在最后忘记使用classmethod()函数封装该方法。

我们一直很想添加某种语法使这种定义更易读,但是直到python2.2发行,我们也没有想出一个好主意。可以说一直到今天,我们也没有找到一个特别满意的方案。然而用户迫切需要一种更直观易记的方法来使用这个新特性,所以在python2.4中添加了函数(方法)修饰符这个特性,相信它可以满足大家的需要。

这个新特性被称为“函数修饰符”。 这个名字来自 classmethod staticmethod,大家经常在函数对象中保存附加信息,它们很大程度上修饰了函数细节。 我们借用了 JAVA中的 @ 符号来做为指示器。使用新的语法,上面的例子可以被写成这样:

   1 class C:
   2    @classmethod
   3    def meth (cls):
   4        ...

上例中 @classmethod 是 meth=classmethod(meth) 语句的速记方式,通常,如果你写成下面这样

   1 @A @B @C
   2 def f ():
   3     ...

它就等同于以下未使用修饰符的语句

   1 def f(): ...
   2 f = A(B(C(f)))

修饰器必须出现在函数定义前一行,不允许和函数定义在同一行。也就是说 @A def f(): 是非法的。 只可以在模块或类定义层内对函数进行修饰,不允许修修饰一个类。

一个修饰符就是一个函数,它将被修饰的函数做为参数,并返回修饰后的同名函数或其它可调用的东西。很容易写出自己的修饰符,下面就是一个简单的例子,它用来设定(被修饰)函数对象的属性。

>>> def deco(func):
...    func.attr = 'decorated'
...    return func
...
>>> @deco
... def f(): pass
...
>>> f
<function f at 0x402ef0d4>
>>> f.attr
'decorated'
>>>

一个有点用的小例子: 下面的修饰器检查提供的参数是否为整数

   1 def require_int (func):
   2     def wrapper (arg):
   3         assert isinstance(arg, int)
   4         return func(arg)
   5     return wrapper
   6 @require_int
   7 def p1 (arg):
   8     print arg
   9 @require_int
  10 def p2(arg):
  11     print arg*2

PEP318中的一个例子包含了该主意的一个空想版本,它让你指定你想要的类型并检查返回的类型。 修饰器函数可以带参数。如果提供了参数,你的修饰器函数被调用时必须返回一个新的修饰器函数,这个新函数必须以一个函数做参数返回另一个函数,就象前面描述的那样。换句话说,@A @B @C(argc) 将变成

   1 def f(): ...
   2 _deco = C(args)
   3 f = A(B(_deco(f)))

好象比较绕,嘿嘿,但并不很难懂, 加个参数化decorator的例子argsDecorator

一个小的相关变动就是 函数的 func_name 属性由只读变为可写。这个属性通常用来在调试时显示函数的名字。修饰符将会改变新生成的函数的这个属性。

WeiZhong/DecoratorsInPython24 (last edited 2009-12-25 07:19:06 by localhost)