原创 Python之装饰器

2018-4-6 13:51 1508 12 12 分类: 软件与OS 文集: Linux笔记

在使用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...”就打印出来了。


结语:

关于装饰器,还有很多很多特性,这里就不一一介绍了。俺作为编写应用的程序员,很多特性都用不上。编写工具的程序员,才会使用的比较多。当然,要使用工具,还是多少了解一些的好。


PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
12
关闭 站长推荐上一条 /3 下一条