在使用Python搭建的轻量级Web框架Flask中,装饰器被大量使用。对于一种语言的高级特性,不需要在刚开始学习它的时候就全部掌握,而是可以在之后的应用中学习并理解。既然Flask用到了装饰器,现在就是时候好好学习并理解它了。否则,使用Flask的过程就变成了“知其然,不知其所以然”,总在朦朦胧胧中啦!
函数装饰器(function decorator)的含义是:
函数装饰器提供了一种方式,替函数明确了特定的运算模式,也就是将函数包裹了另一层,在另一函数的逻辑内实现。
函数装饰器写成一行,在def语句之前,由@符号、metafunction组成。
静态方法可以写成这样:
class Cake:
kind = 0
def __init__(self, fruit):
self.fruit = fruit
Cake.kind = Cake.kind + len(fruit)
@staticmethod
def printkind():
print("kind = ", Cake.kind)
x = Cake(['apple', 'banana', 'orange'])
Cake.printkind()
x.printkind()
运行结果:
kind = 3
kind = 3
这个和下面的语句效是一样的:
printkind = staticmethod(printkind)
staticmethod是一个内置函数,这里装饰器的好处还没有显示出来。好像@staticmethod和staticmethod()的效果没什么区别嘛!不要着急,接下来就可以编写自己的函数装饰器:
class Cake:
def __init__(self, func):
self.calls = 0
self.func = func
print('__init__: ', self.calls, self.func)
def __call__(self, *args):
self.calls += 1
print('__call__: ', self.calls, self.func, *args)
self.func(*args)
@Cake
def add_drink(drink):
print('drink: ', drink)
@Cake
def add_cereal(cereal):
print('cereal: ', cereal)
add_drink(['water', 'juice'])
add_drink(['coffee', 'coco'])
add_cereal(['rice', 'grain'])
执行结果:
__init__: 0 <function add_drink at 0x7fd68854a510>
__init__: 0 <function add_cereal at 0x7fd67e66b400>
__call__: 1 <function add_drink at 0x7fd68854a510> ['water', 'juice']
drink: ['water', 'juice']
__call__: 2 <function add_drink at 0x7fd68854a510> ['coffee', 'coco']
drink: ['coffee', 'coco']
__call__: 1 <function add_cereal at 0x7fd67e66b400> ['rice', 'grain']
cereal: ['rice', 'grain']
发现规律了么?
使用@Cake装饰add_drink时,执行函数定义,也即def语句,Cake的构造函数被调用。执行add_drink时,Cake的__call__方法被调用。最后才是add_drink本身的内容调用。也就是说,本来这是一个简单的函数,增加了Cake装饰器之后,可以使用类Cake的方法。我们可以记录它被调用的次数,还能打印它的入口参数。
这就是为什么decorator被称为decorator,为什么将这种功能称为装饰器。
假如我们有一个房子,在墙上装饰了一个闹钟,那么我们在使用这个房子的时候,就获得了闹钟的方法。在窗户了装饰了一幕帘子,那么就获得了帘子的方法。
现在我们探索一下Flask的语法:
@app.route('/')
def mainpage():
return render_template('main.html')
本来我们只有一个简单的函数mainpage,现在使用@app.route('/')来装饰它,那么mainpage就获得了app.route('/')的方法。这些方法替我们完成了后台工作,在后台工作完成之后,执行最后定义的render_template函数,也即返回main.html页面。
装饰器极大简化了Flask的用户代码!我们都不用进行app的构造,也不用执行后台的__init__或其他操作,直接定义自己的用户函数就可以啦!
类装饰器:
不仅函数可以使用装饰器,类也可以使用装饰器:
def decorate_x(x):
print('I am decorating...')
return x
@decorate_x
class Shop():
def __init__(self):
print('I am Shop!')
def __call__(self, *args):
print('Shop __call__: ', *args)
x = Shop()
x('buy')
运行结果:
I am decorating...
I am Shop!
Shop __call__: buy
之前是函数使用类来装饰,这里是类使用函数装饰。当类Shop被decorate_x装饰时,首先执行了decorate_x内部的内容,入口参数是自身,且返回自身。接下来才是构造函数和__call__被执行。
要注意的是,当装饰器语句被定义时,它的内容就会运行了。所以在@语句处,“I am decorating...”就打印出来了。
结语:
关于装饰器,还有很多很多特性,这里就不一一介绍了。俺作为编写应用的程序员,很多特性都用不上。编写工具的程序员,才会使用的比较多。当然,要使用工具,还是多少了解一些的好。
文章评论(0条评论)
登录后参与讨论