【Python实践】_装饰器

真正的稳定,是自己不断成长,不断寻找新的空间。与其要稳定,不如开始拥抱这个变化的时代,让自己准备好。


python实践

【目录】Python实践

【写在前面】:
曾经在面试的时候问过很多人“什么是装饰器?”,但是都没有得到一个很简洁明了的答案,希望这篇文章能使你对装饰器有个比较清楚、简洁的认识。
【材料】:
参考材料 《Python进阶》

【Step1】:什么是装饰器?
从字面意思来理解,装饰+器,装饰我们都知道,是在原有基础上增加某些功能,达到一定的效果,python中的装饰器也是在原来函数(类)上增加一些特殊的功能,但是并不是直接去修改原来的函数(类),而是新写一个函数,这个函数的功能就是在对原函数(类)二次处理(并非重构)
简单举例如下:

# -*- coding: utf-8 -*-
def greet(fun):
    def pre():
        print("I'm pre")
        t = fun()
        return t
    return pre


@greet
def test():
    return "I'm test"


if __name__ == '__main__':
    print(test())

运行结果如下:

I'm pre
I'm test

上面的greet函数就是一个装饰器,其作用就是对test函数做装饰,在待装饰的函数前面使用@符号来调用装饰函数。
【Step2】:对Step1的解释
1、对函数的认识,通常def test()被叫做定义一个test函数,这其中test是函数名,当使用test()时表示在调用该函数,可以拿到return值,当使用test时并不会调用,只是将函数作为一个变量,可以赋值给其他变量,比如a,这样a变量就有了test函数的功能,而且两个函数名都指向该函数的内存地址(0x012B5618)。这里我们了解到原来函数不是只能直接被调用,函数名还能够作为参数使用,这一点很重要。

def test():
    return "I'm test"


if __name__ == '__main__':
    print(test())
    print(test)
    a = test
    print(a)
    print(a())
    del test
    print(a())

运行结果如下:

I'm test
<function test at 0x00B25618>
<function test at 0x00B25618>
I'm test
I'm test

2、函数中定义函数
函数out中包含子函数inner,调用out函数时,会return出该函数的输出,即“here is out...”,在out函数内部有print(inner())来打印inner函数的return结果,即“here is inner...”(如果没有这一句,是不会调用inner函数的),而由于inner函数是在out函数内部的,所以不能被单独调用。
举例如下:

def out():
    print("here is out...")

    def inner():
        return "here is inner..."
    print(inner())


out()
inner()

运行结果如下:

here is out...
here is inner...
  File "D:/auto_case/DailyWork/test.py", line 10, in <module>
    inner()
NameError: name 'inner' is not defined

3、从函数中返回函数
现实中很少会在函数中去执行一个函数,更多的时候是希望将内部函数作为外层函数的return值,所以我们可以这样改造,达到返回内层函数的效果
(1).out函数,这个就是out的一个函数,return a
(2).out1函数,内层inner1函数,在out1函数中使用inner1()调用inner1,返回inner1函数return的值;
(3).out2函数,内层inner2函数,在out2函数中使用inner2将函数赋值给了变量c,返回函数c(注意不是函数c被调用的值);
(4).out3函数是对out2函数的简写,功能一样;
(5).在print中,重点是out3()是一个函数,所以要得到函数返回值,就需要在其后面加上小括号,达到调用函数的效果,即out3()()。
举例如下:

# -*- coding: utf-8 -*-
def out():
    a = "test"
    return a


def out1():
    def inner1():
        return "here is inner..."
    b = inner1()
    return b


def out2():
    def inner2():
        return "here is inner2..."
    c = inner2
    return c


def out3():
    def inner3():
        return "here is inner3..."
    return inner3


print(out())
print(out1())
print(out2())
d = out2()
print(d())
print(out3())
print(out3()())

运行结果如下:

test
here is inner...
<function out2.<locals>.inner2 at 0x01A3D8E8>
here is inner2...
<function out3.<locals>.inner3 at 0x01A3D618>
here is inner3...

4、将函数名作为参数传递给其他函数
函数名可以代表函数,也可以赋值,所以能够作为参数专递到函数中去,在函数中只要在参数后面加上小括号,就拥有了该函数的功能。我在下面的函数中加了步骤输出,读者可以比较清楚的知道函数是如何调用的。
举例如下:

# -*- coding: utf-8 -*-
def test():
    print("step 4")
    return "I'm test"


def greet(fun):
    print("step 1")
    
    def pre():
        print("step 2")
        print("I'm pre")
        t = fun()
        return t
    print("step 3")
    return pre


print(greet(test))
print(greet(test)())

运行结果如下:

C:\Users\54788\AppData\Local\Programs\Python\Python35-32\python3.exe D:/auto_case/DailyWork/test.py
step 1
step 3
<function greet.<locals>.pre at 0x01C0D588>
~~~~~~虚拟分割线~~~~~~~
step 1
step 3
step 2
I'm pre
step 4
I'm test

Process finished with exit code 0

5、装饰器标识符“@”,使用@装饰器名在待装饰函数前,即可完成不修改待装饰函数的情况下,修改函数的功能,注意装饰器必须在被装饰函数前定义。
【Step3】:应用场景举例
鉴权在打开页面和登录中的使用

# -*- coding: utf-8 -*-
def auth(fun):
    def base_auth(*param):
        if param[0] == '123%$&*sdhjd':
            return fun(*param)
        else:
            return no_auth()
    return base_auth


def no_auth():
    return "you have no auth"


@auth
def open_page(param):
    return "begin to open page..." + str(param)


@auth
def login(param1,param2):
    return "begin to login..." + str(param2)


print(open_page('123%$&*sdhjd'))
print(open_page('123%$&*'))
print(login('123%$&*sdhjd', 'test'))
print(login('123%$&*', 'test'))

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

推荐阅读更多精彩内容