Python有大量强大又贴心的特性,如果要列个最受欢迎排行榜,那么装饰器绝对会在其中。
初识装饰器,会感觉到优雅且神奇,想亲手实现时却总有距离感,就像深闺的冰美人一般。这往往是因为理解装饰器时把其他的一些概念混杂在一起了。待我抚去层层面纱,你会看到纯粹的装饰器其实蛮简单直率的。
装饰器的原理
在解释器下跑个装饰器的例子,直观地感受一下。
# make_bold就是装饰器,实现方式这里略去
>>> @make_bold... def get_content():... return 'hello world'...>>> get_content()'<b>hello world</b>'
被 make_bold 装饰的 get_content ,调用后返回结果会自动被 b 标签包住。怎么做到的呢,简单4步就能明白了。
1. 函数是对象
我们定义个 get_content 函数。这时 get_content 也是个对象,它能做所有对象的操作。
def get_content(): return 'hello world'
它有 id ,有 type ,有值。
>>> id(get_content)140090200473112>>> type(get_content)<class 'function'>>>> get_content<function get_content at 0x7f694aa2be18>
跟其他对象一样可以被赋值给其它变量。
>>> func_name = get_content>>> func_name()'hello world'
它可以当参数传递,也可以当返回值
>>> def foo(bar):... print(bar())... return bar...>>> func = foo(get_content)hello world>>> func()'hello world'
2. 自定义函数对象
我们可以用 class 来构造函数对象。有成员函数 __call__ 的就是函数对象了,函数对象被调用时正是调用的 __call__ 。
class FuncObj(object): def __init__(self, name): print('Initialize') self.name= name def __call__(self): print('Hi', self.name)
我们来调用看看。可以看到, 函数对象的使用分两步:构造和调用 (同学们注意了,这是考点)。
>>> fo = FuncObj('python')Initialize>>> fo()Hi python
3. @ 是个语法糖
装饰器的 @ 没有做什么特别的事,不用它也可以实现一样的功能,只不过需要更多的代码。
@make_bolddef get_content(): return 'hello world'# 上面的代码等价于下面的def get_content(): return 'hello world'get_content = make_bold(get_content)
make_bold 是个函数,要求入参是函数对象,返回值是函数对象。 @ 的语法糖其实是省去了上面最后一行代码,使可读性更好。用了装饰器后,每次调用 get_content ,真正调用的是 make_bold 返回的函数对象。
新闻热点
疑难解答