08_Python装饰器函数_全栈开发学习笔记

1. 装饰器开篇_time模块

范例1:
time.sleep():让程序在执行到这个位置的时候停一会儿

import time

time.sleep(5)
print("哇咔咔")

执行结果:

# 先停5秒
哇咔咔


范例2:
time.time():获取当前时间(从1970年到现在的总秒数)

import time

print(time.time())

执行结果:

1539995896.847099


范例3:
统计代码执行的时间

import time

def func():
    start = time.time()
    print("世界大同")
    time.sleep(0.01)
    end = time.time()
    print(end-start)
func()

执行结果

世界大同
0.010123491287231445


范例4.1:
将范例3函数内的时间与打印分开,各自独立成一个函数

import time

def timer(f):    # 计算函数执行的时间
    start = time.time()
    f()
    end = time.time()
    print(end-start)

def func():
    time.sleep(0.01)
    print("世界大同")

timer(func)

执行结果

世界大同
0.010216474533081055


范例4.2:
同范例4.1,容易理解的方式

import time

def func():
    time.sleep(0.01)
    print("世界大同")

def timer():
    start = time.time()
    func()
    end = time.time()
    print(end-start)

timer()

执行结果:

世界大同
0.010337352752685547


范例5:
进一步优化范例4

import time

def func():    # 第一步
    time.sleep(0.01)    # 第十步
    print("世界大同")    # 第十一步

def timer(f):    # 第二步:f为func的内存地址    # 装饰器函数
    def inner():    # 第四步
        start = time.time()    # 第八步
        f()    # 第九步 # 被装饰的函数
        end = time.time()    # 第十二步
        print(end-start)    # 第十三步
    return inner    # 第五步

func = timer(func)    # 第三步:等号右边    # 第六步:等号左边
func()    # 第七步:执行inner()

执行结果

世界大同
0.01023554801940918


1.1 装饰器的作用

装饰器的作用 —— 不想修改函数的调用方式 但是还想在原来的函数前后添加功能
timmer就是一个装饰器函数,只是对一个函数有一些装饰作用。


2 语法糖

import time

def timer(f):    # 装饰器函数
    def inner():
        start = time.time()
        f()    # 被装饰的函数
        end = time.time()
        print(end-start)
    return inner

@timer    # 语法糖  @装饰器函数名
def func():    # 被装饰的函数
    time.sleep(0.01)
    print("世界大同")

#func = timer(func)    # 被语法糖代替
func()

执行结果

世界大同
0.010994911193847656

3 取得被装饰函数的返回值

import time

def timer(f):    # 装饰器函数
    def inner():
        start = time.time()
        ret = f()    # 被装饰的函数
        end = time.time()
        print(end-start)
        return ret
    return inner

@timer    # 语法糖
def func():
    time.sleep(0.01)
    print("世界大同")
    return "新年好"

#func = timer(func)    # 被语法糖代替
ret = func()
print(ret)

执行结果

世界大同
0.010995149612426758
新年好

4 装饰带一个参数函数的装饰器

范例:

import time

def timer(f):    # 装饰器函数
    def inner(a):
        start = time.time()
        ret = f(a)    # 被装饰的函数
        end = time.time()
        print(end-start)
        return ret
    return inner

@timer    # 语法糖
def func(a):
    time.sleep(0.01)
    print("世界大同",a)
    return "新年好"

#func = timer(func)    # 被语法糖代替
ret = func(1)
print(ret)

执行结果

世界大同 1
0.010066032409667969
新年好

5 装饰带万能参数函数的装饰器

范例:

import time

def timer(f):    # 装饰器函数
    def inner(*args,**kwargs):
        start = time.time()
        ret = f(*args,**kwargs)    # 被装饰的函数
        end = time.time()
        print(end-start)
        return ret
    return inner

@timer    # 语法糖
def func(a,b):
    time.sleep(0.01)
    print("世界大同",a,b)
    return "新年好"

@timer    # 语法糖
def func1(a):
    time.sleep(0.01)
    print("世界大同",a)
    return "新年好"

#func = timer(func)    # 被语法糖代替
ret = func(1,2)
ret = func(1,b = 2)
print(ret)

执行结果

世界大同 1 2
0.010993003845214844
世界大同 1 2
0.010015010833740234
新年好

6 装饰器的固定格式

详解:

def wrapper(f):    #装饰器函数,f是被装饰的函数
    def inner(*args,**kwargs):
        '''在被装饰函数之前要做的事'''
        ret = f(*args,**kwargs)    #被装饰的函数
        '''在被装饰函数之后要做的事'''
        return ret
    return inner

@wrapper         #语法糖 @装饰器函数名
def func(a,b):     #被装饰的函数
    time.sleep(0.01)
    print('老板好同事好大家好',a,b)
    return '新年好'


粗解:

def wrapper(func):   #qqxing
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)   #被装饰的函数
        return ret
    return inner

@wrapper        #qqxing = wrapper(qqxing)
def qqxing():
    print(123)

ret = qqxing()   #inner


复习时的例子:

def wrapper(func):    # 第一步
    def inner(*args,**kwargs):    # 第三步
        print('在被装饰的函数执行之前做的事')    # 第七步
        ret = func(*args,**kwargs)# 第八步 等号右边:holiday(*(3),**{})    # 第十一步:等号左边,接收了第十步的返回值
        print('在被装饰的函数执行之后做的事')    # 第十二步
        return ret    # 第十三步
    return inner    # 第四步

@wrapper   #holiday = wrapper(holiday)    # 第二步:执行等号右边    # 第五步:等号左边,此时的holiday就等于inner
def holiday(day):
    print('全体放假%s天'%day)    # 第九步
    return '好开心'    # 第十步

ret = holiday(3)    # 第六步:等号右边 inner(3)    # 第十四步,接收第十三步的返回值
print(ret)    # 第十五步

执行结果:

在被装饰的函数执行之前做的事
全体放假3天
好开心
在被装饰的函数执行之后做的事


另一个说明:

def outer(*args):    # 接收 聚合
    print(args)
    print(*args)    # 调用 打散
    def inner(*args):    # 接收 聚合
        print('inner : ',args)
    inner(*args)    # 调用 打散


outer(1,2,3,4)   #==outer(*[1,2,3,4])  #==outer(*(1,2,3,4))

7 查看函数信息的方法

7.1 查看字符串格式的函数名

范例:_name_

def wahaha():
    print("哇咔咔")

print(wahaha.__name__)

执行结果

wahaha


7.2 查看函数内的注释文档

范例:_doc_

def wahaha():
    """
    一个打印哇哈哈的函数
    :return:
    """
    print("哇咔咔")

print(wahaha.__doc__)

执行结果

    一个打印哇哈哈的函数
    :return:


7.3 装饰器:wraps

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

范例1:未使用@wraps

#from functools import wraps

def wrapper(func):  #func = holiday
    #@wraps(func)
    def inner(*args,**kwargs):
        print('在被装饰的函数执行之前做的事')
        ret = func(*args,**kwargs)
        print('在被装饰的函数执行之后做的事')
        return ret
    return inner

@wrapper   #holiday = wrapper(holiday)
def holiday(day):
    '''这是一个放假通知'''
    print('全体放假%s天'%day)
    return '好开心'

print(holiday.__name__)

执行结果

inner


范例2:使用@wraps

from functools import wraps

def wrapper(func):  #func = holiday
    @wraps(func)    # 加在最内层函数正上方
    def inner(*args,**kwargs):
        print('在被装饰的函数执行之前做的事')
        ret = func(*args,**kwargs)
        print('在被装饰的函数执行之后做的事')
        return ret
    return inner

@wrapper   #holiday = wrapper(holiday)
def holiday(day):
    '''这是一个放假通知'''
    print('全体放假%s天'%day)
    return '好开心'

print(holiday.__name__)
print(holiday.__doc__)

ret = holiday(3)   #inner
print(ret)

执行结果

holiday
这是一个放假通知

在被装饰的函数执行之前做的事
全体放假3天
在被装饰的函数执行之后做的事
好开心

8 带参数的装饰器(三层函数)

范例1.1:给装饰器一个控制开关(开)

import time
FLAGE = True
def timmer_out(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end-start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer

# 第二种理解 timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)    # 第一种理解 timmer_out(FLAG) == timmer    @timmer == wahaha = timmer(wahaha)
def wahaha():
    time.sleep(0.1)
    print('wahahahahahaha')

@timmer_out(FLAGE)
def erguotou():
    time.sleep(0.1)
    print('erguotoutoutou')

wahaha()
erguotou()

执行结果:

wahahahahahaha
0.10094094276428223
erguotoutoutou
0.10099601745605469


范例1.2:给装饰器一个控制开关(关)

# 关
import time
FLAGE = False
def timmer_out(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end-start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer

# timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)
def wahaha():
    time.sleep(0.1)
    print('wahahahahahaha')

@timmer_out(FLAGE)
def erguotou():
    time.sleep(0.1)
    print('erguotoutoutou')

wahaha()
erguotou()

执行结果:

wahahahahahaha
erguotoutoutou

9 多个装饰器装饰一个函数

双层装饰器可用于:
1.1 记录用户的登录情况
1.2 计算这个函数的执行时间

范例1.1:双层装饰器1

def wrapper1(func):    # 第一步    # 第三之后 func -> f
    def inner1():    # 第四步
        print('wrapper1 ,before func')    # 第十五步    # 第二执行
        func()    # 第十六步  f()
        print('wrapper1 ,after func')    # 第十八步    # 第四执行
    return inner1    # 第五步

def wrapper2(func):    # 第二步    # 第七步之后 func --> inner1
    def inner2():    # 第八步
        print('wrapper2 ,before func')    # 第十三步    # 第一执行
        func()    # 第十四步  inner1()
        print('wrapper2 ,after func')    # 第十九部    # 第五执行
    return inner2    # 第九步

@wrapper2    # 第七步 f = wrapper2(f) wrapper(inner1)    # 第十步 f = wrapper2(f) wrapper(inner1) = inner2
@wrapper1    # 第三步 f = wrapper1(f)    # 第六步 f = wrapper1(f) = inner1
def f():
    print('in f')    # 第十七步    # 第三执行

f()    # 第十一步 执行了inner2()

执行结果

wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func


范例1.2:双层装饰器2

def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')   # 第一执行
        func()
        print('wrapper1 ,after func')   # 第五执行
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')   # 第二执行
        func()
        print('wrapper2 ,after func')   # 第四执行
    return inner2

@wrapper1
@wrapper2
def f():
    print('in f')   # 第三执行

f()

执行结果:

wrapper1 ,before func
wrapper2 ,before func
in f
wrapper2 ,after func
wrapper1 ,after func


范例2:三层装饰器

def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        ret = func()
        print('wrapper1 ,after func')
        return ret
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        ret = func()
        print('wrapper2 ,after func')
        return ret
    return inner2

def wrapper3(func):
    def inner3():
        print('wrapper3 ,before func')
        ret = func()
        print('wrapper3 ,after func')
        return ret
    return inner3

@wrapper3
@wrapper2
@wrapper1   # f = wra
def f():
    print('in f')
    return '哈哈哈'
print(f())

执行结果

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

推荐阅读更多精彩内容

  • 包(lib)、模块(module) 在Python中,存在包和模块两个常见概念。 模块:编写Python代码的py...
    清清子衿木子水心阅读 3,797评论 0 27
  • 终于可以回家了,我的心情很明媚。尽管晚上咳嗽咳醒N次,觉睡得断断续续,可我还是开心的想放声高歌。五点开始听广播,六...
    逸琼阅读 291评论 0 4
  • 在大家都在熬夜等待零点抢单时,估计都忘记双11是光棍节了吧。晚上还跟他打趣今天大家都陪我们过节,庆祝我们4...
    Elaine鲍彦君阅读 303评论 0 0
  • 今晚很晚,想写一点东西,但不知道该如何写。发一张最近的状态吧,上周六跟朋友一块儿聚餐。 师恩有愧,做人无悔 今天上...
    y飞舞的燕子y阅读 210评论 0 0
  • 有时候,你真的不知道,别人发过来的一张照片究竟是在说这件事情,还是在炫耀着什么。。。是我太多疑,还是别人的心思太多。
    雅福阅读 168评论 0 0