|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
装饰器揭秘
前面的例子,我们可以使用装饰器的语法:
- @my_shiny_new_decorator
- def another_stand_alone_function() :
- print "Leave me alone"
-
- another_stand_alone_function()
- #输出 :
- #Before the function runs
- #Leave me alone
- #After the function runs
- 当然你也可以累积装饰:
- def bread(func) :
- def wrapper() :
- print "</''''''\>"
- func()
- print "<\______/>"
- return wrapper
-
- def ingredients(func) :
- def wrapper() :
- print "#tomatoes#"
- func()
- print "~salad~"
- return wrapper
-
- def sandwich(food="--ham--") :
- print food
-
- sandwich()
- #输出 : --ham--
- sandwich = bread(ingredients(sandwich))
- sandwich()
- #outputs :
- #</''''''\>
- # #tomatoes#
- # --ham--
- # ~salad~
- #<\______/>
复制代码
使用python装饰器语法:
- @bread
- @ingredients
- def sandwich(food="--ham--") :
- print food
-
- sandwich()
- #输出 :
- #</''''''\>
- # #tomatoes#
- # --ham--
- # ~salad~
- #<\______/>
复制代码
装饰器的顺序很重要,需要注意:
- @ingredients
- @bread
- def strange_sandwich(food="--ham--") :
- print food
-
- strange_sandwich()
- #输出 :
- ##tomatoes#
- #</''''''\>
- # --ham--
- #<\______/>
- # ~salad~
- 最后回答前面提到的问题:
- # 装饰器makebold用于转换为粗体
- def makebold(fn):
- # 结果返回该函数
- def wrapper():
- # 插入一些执行前后的代码
- return "<b>" + fn() + "</b>"
- return wrapper
-
- # 装饰器makeitalic用于转换为斜体
- def makeitalic(fn):
- # 结果返回该函数
- def wrapper():
- # 插入一些执行前后的代码
- return "<i>" + fn() + "</i>"
- return wrapper
-
- @makebold
- @makeitalic
- def say():
- return "hello"
-
- print say()
- #输出: <b><i>hello</i></b>
-
- # 等同于
- def say():
- return "hello"
- say = makebold(makeitalic(say))
-
- print say()
- #输出: <b><i>hello</i></b>
复制代码
内置的装饰器
内置的装饰器有三个,分别是staticmethod、classmethod和property,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。而属性也不是不可或缺的,Java没有属性也一样活得很滋润。从我个人的Python经验来看,我没有使用过property,使用staticmethod和classmethod的频率也非常低。
- class Rabbit(object):
-
- def __init__(self, name):
- self._name = name
-
- @staticmethod
- def newRabbit(name):
- return Rabbit(name)
-
- @classmethod
- def newRabbit2(cls):
- return Rabbit('')
-
- @property
- def name(self):
- return self._name
复制代码
这里定义的属性是一个只读属性,如果需要可写,则需要再定义一个setter:
- @name.setter
- def name(self, name):
- self._name = name
复制代码
functools模块
functools模块提供了两个装饰器。这个模块是Python 2.5后新增的,一般来说大家用的应该都高于这个版本。
2.3.1. wraps(wrapped[, assigned][, updated]):
这是一个很有用的装饰器。看过前一篇反射的朋友应该知道,函数是有几个特殊属性比如函数名,在被装饰后,上例中的函数名foo会变成包装函数的名字wrapper,如果你希望使用反射,可能会导致意外的结果。这个装饰器可以解决这个问题,它能将装饰过的函数的特殊属性保留。
- import time
- import functools
-
- def timeit(func):
- @functools.wraps(func)
- def wrapper():
- start = time.clock()
- func()
- end =time.clock()
- print 'used:', end - start
- return wrapper
-
- @timeit
- def foo():
- print 'in foo()'
-
- foo()
- print foo.__name__
复制代码
首先注意第5行,如果注释这一行,foo.__name__将是'wrapper'。另外相信你也注意到了,这个装饰器竟然带有一个参数。实际上,他还有另外两个可选的参数,assigned中的属性名将使用赋值的方式替换,而updated中的属性名将使用update的方式合并,你可以通过查看functools的源代码获得它们的默认值。对于这个装饰器,相当于wrapper = functools.wraps(func)(wrapper)。
2.3.2. total_ordering(cls):
这个装饰器在特定的场合有一定用处,但是它是在Python 2.7后新增的。它的作用是为实现了至少__lt__、__le__、__gt__、__ge__其中一个的类加上其他的比较方法,这是一个类装饰器。如果觉得不好理解,不妨仔细看看这个装饰器的源代码:
- def total_ordering(cls):
- 54 """Class decorator that fills in missing ordering methods"""
- 55 convert = {
- 56 '__lt__': [('__gt__', lambda self, other: other < self),
- 57 ('__le__', lambda self, other: not other < self),
- 58 ('__ge__', lambda self, other: not self < other)],
- 59 '__le__': [('__ge__', lambda self, other: other <= self),
- 60 ('__lt__', lambda self, other: not other <= self),
- 61 ('__gt__', lambda self, other: not self <= other)],
- 62 '__gt__': [('__lt__', lambda self, other: other > self),
- 63 ('__ge__', lambda self, other: not other > self),
- 64 ('__le__', lambda self, other: not self > other)],
- 65 '__ge__': [('__le__', lambda self, other: other >= self),
- 66 ('__gt__', lambda self, other: not other >= self),
- 67 ('__lt__', lambda self, other: not self >= other)]
- 68 }
- 69 roots = set(dir(cls)) & set(convert)
- 70 if not roots:
- 71 raise ValueError('must define at least one ordering operation: < > <= >=')
- 72 root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
- 73 for opname, opfunc in convert[root]:
- 74 if opname not in roots:
- 75 opfunc.__name__ = opname
- 76 opfunc.__doc__ = getattr(int, opname).__doc__
- 77 setattr(cls, opname, opfunc)
- 78 return cls
复制代码 |
|