装饰器

写在前面

首先理解下,python的装饰器@mydec是一个语法糖,它的本质是func = mydec(func),也就是说把函数func作为参数传入在mydec中。

引子

假设一个函数要打印用户的姓名、年龄、性别当然还有其他Blablabla…

def print_human_information(name, age, sex):
    print("name is {}, age is {}, sex is {}.".format(name, age, sex))
    
if __name__ == "__main__":
    print_human_information(name="Lee", age=-10, sex='unknown')

然后突然你想看下这个函数执行花了多少时间,可能你会这么写:

import time

def print_human_information(name, age, sex):
    start = time.clock()
    
    print("name is {}, age is {}, sex is {}.".format(name, age, sex))
    
    end = time.clock()
    print "execute in {:.2f} ms".format((end - start) * 1000)
    
if __name__ == "__main__":
    print_human_information(name="Lee", age=-10, sex='unknown')

增加一个start,一个end,完美!
但是,如果再有一个函数不打印human,打印animal呢?Ctrl+C、V?太low逼!我们有更好的办法解决这个问题。

import time

def timeused(function):
    def wrapper(name, age, sex):
        start = time.clock()
        
        function(name, age, sex)
        
        end = time.clock()
        print "execute in {:.2f} ms".format((end - start) * 1000)
    return wrapper
        
def print_human_information(name, age, sex):
    print("name is {}, age is {}, sex is {}.".format(name, age, sex))

# 看这里,看这里,看这里
# 重要的事情说三遍
print_human_information = timeused(print_human_information)    
    
if __name__ == "__main__":
    print_human_information(name="Lee", age=-10, sex='unknown')

现在只要有了print_human_information = timeused(print_human_information)main函数中不需要做任何修改就可以显示函数执行的时间,接着让我们再来一个更简洁的语法。

@timeused
def print_human_information(name, age, sex):
    …

完美!

进阶

现在打印animal的函数真的来了,然而参数个数只有两个:

@timeused
def print_animal_information(name, age):
    print("name is {}, age is {}.".format(name, age))

好吧,timeused报错了,修改内嵌函数以及function的参数形式如下,支持任意多个参数:

def timeused(function):
    def wrapper(*args, **kwargs):
        start = time.clock()

        function(*args, **kwargs)
        
        end = time.clock()
        print "execute in {:.2f} ms".format((end - start) * 1000)
    return wrapper

God祥曾经教导我们:

一旦满足了某个需求,那么接下来类似的需求就会接踵而至。

很快,我们需要一个装饰器来检查print_human_informationprint_animal_informationagesex的合法性。(如年龄不能为负数,人类性别只能是male或者female,而对于动物我们不关心,因此该项不检查)
或许,现在是时候编写一个包含参数的装饰器了!

# 默认不检查年龄和性别
def check(check_age = False, check_sex = False):
    def wrapper(function):
        def _wrapper(*args, **kwargs):
            
            if check_age:
                _age = kwargs['age']
                if _age < 0 or _age > 140:
                    print "invalid age '{}', use default {}.".format(_age, 0)  
                    kwargs['age'] = 0
            
            if check_sex:
                _sex = kwargs['sex']
                if _sex != 'male' or _sex != 'female':
                    print "invalid sex '{}', use default {}.".format(_sex, 'male')
                    kwargs['sex'] = 'male'
                    
            function(*args, **kwargs)
            # 用于展示装饰器嵌套的效果
            time.sleep(0.5)
            
        return _wrapper
    return wrapper

@check(check_age = True, check_sex = True)
@timeused
def print_human_information(name, age, sex):
    …
    
@timeused 
@check(check_age = True)
def print_animal_information(name, age):
  …

资料

Python装饰器学习(九步入门)
PEP 0318 -- Decorators for Functions and Methods
PythonDecoratorLibrary

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,...
    chen_000阅读 1,360评论 0 3
  • 本文为《爬着学Python》系列第四篇文章。从本篇开始,本专栏在顺序更新的基础上,会有不规则的更新。 在Pytho...
    SyPy阅读 2,489评论 4 11
  • 装饰是为函数和类指定管理代码的一种方式.装饰器本身的形式是处理其他的可调用对象的可调用的对象。 函数装饰器在函数定...
    低吟浅唱1990阅读 222评论 0 0
  • 呵呵!作为一名教python的老师,我发现学生们基本上一开始很难搞定python的装饰器,也许因为装饰器确实很难懂...
    TypingQuietly阅读 19,518评论 26 186
  • 煮毛豆、花生、西红柿牛腩……我不顾形象地把餐桌上一切我能吃的东西往嘴里塞,最后当大家都放下筷子我还恬不知耻地...
    桃子在寻找阅读 411评论 0 2