= 5 PEP 318函数和方法的修饰符 = * '''[[http://www.python.org/dev/peps/pep-0318/|pep-0318]]''' python 2.2 虽然通过添加静态方法和类方法扩展了python对象模型,却没有提供定义静态方法或类方法的新语法。你只能象通常方式那样写一个函数定义语句,然后将该函数作为参数传递给staticmethod()或classmethod()来将其封装成一个新类型的方法。你的代码看起来就象下面这样: {{{ #!python class C: def meth (cls): ... meth = classmethod(meth) # Rebind name to wrapped-up class method 将属性名重新绑定到封装后的类方法 }}} 如果这个方法定义很长的话,很容易在最后忘记使用{{{classmethod()}}}函数封装该方法。 我们一直很想添加某种语法使这种定义更易读,但是直到python2.2发行,我们也没有想出一个好主意。可以说一直到今天,我们也没有找到一个特别满意的方案。然而用户迫切需要一种更直观易记的方法来使用这个新特性,所以在python2.4中添加了函数(方法)修饰符这个特性,相信它可以满足大家的需要。 这个新特性被称为“函数修饰符”。 这个名字来自 classmethod staticmethod,大家经常在函数对象中保存附加信息,它们很大程度上修饰了函数细节。 我们借用了 JAVA中的 @ 符号来做为指示器。使用新的语法,上面的例子可以被写成这样: {{{ #!python class C: @classmethod def meth (cls): ... }}} 上例中 {{{@classmethod 是 meth=classmethod(meth)}}} 语句的速记方式,通常,如果你写成下面这样 {{{ #!python @A @B @C def f (): ... }}} 它就等同于以下未使用修饰符的语句 {{{ #!python def f(): ... f = A(B(C(f))) }}} 修饰器必须出现在函数定义前一行,不允许和函数定义在同一行。也就是说 @A def f(): 是非法的。 只可以在模块或类定义层内对函数进行修饰,不允许修修饰一个类。 一个修饰符就是一个函数,它将被修饰的函数做为参数,并返回修饰后的同名函数或其它可调用的东西。很容易写出自己的修饰符,下面就是一个简单的例子,它用来设定(被修饰)函数对象的属性。 {{{ >>> def deco(func): ... func.attr = 'decorated' ... return func ... >>> @deco ... def f(): pass ... >>> f >>> f.attr 'decorated' >>> }}} 一个有点用的小例子: 下面的修饰器检查提供的参数是否为整数 {{{ #!python def require_int (func): def wrapper (arg): assert isinstance(arg, int) return func(arg) return wrapper @require_int def p1 (arg): print arg @require_int def p2(arg): print arg*2 }}} PEP318中的一个例子包含了该主意的一个空想版本,它让你指定你想要的类型并检查返回的类型。 修饰器函数可以带参数。如果提供了参数,你的修饰器函数被调用时必须返回一个新的修饰器函数,这个新函数必须以一个函数做参数返回另一个函数,就象前面描述的那样。换句话说,@A @B @C(argc) 将变成 {{{ #!python def f(): ... _deco = C(args) f = A(B(_deco(f))) }}} 好象比较绕,嘿嘿,但并不很难懂, 加个参数化decorator的例子[[argsDecorator]] 一个小的相关变动就是 函数的 func_name 属性由只读变为可写。这个属性通常用来在调试时显示函数的名字。修饰符将会改变新生成的函数的这个属性。