Python之装饰器

一、概念:

    装饰器常用于对已经上线的代码,不做任何变动的情况增加额外功能;装饰器本质上也是一个函数,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

    装饰器由:1:高阶函数,、2:内嵌函数、3:闭包 ;三个组成。

    高阶函数:     

def bar():
    print("in the bar")
def foo(func):
    print(func)
    rs = func()
    return  rs
foo(bar)

    运行结果:

<function bar at 0x037914F8>
in the bar

    代码讲解:程序从上往下执行,定义bar和foo两个函数,执行foo(bar),将bar函数内存地址当做变量传给foo里的func, 此时打印func为bar函数的地址,即func()等价于bar(),且将结果赋值给rs, 并通过return返回。

    内嵌函数:

def foo():
    def bar():
        rs = print("in the bar")
    bar()

foo()

    运行结果:

in the bar

    代码讲解: 当程序运行到foo()时,foo()内部定义一个bar()函数,并且执行foo函数里的bar(),进行调用。

    闭包:内部函数对外部函数作用域内的变量的引用(非全局变量),则称内部函数为闭包

    
def test(number):
    print("--1--")
    def test_in(number2):
        print("--3--")
        print(number+number2)
    print("--2--")
    return test_in

ret = test(100)
ret(1)
 运行结果:
--1--
--2--
--3--
101

    代码讲解:程序在运行时,先定义test这个函数,然后执行ret = test(100) ;此时将100传递给number, 而test()这个函数,返回test_in,返回的结果是test_in()这个函数的地址, 即ret = test(100),只是将ret指向于test_in()函数的内存地址,并给number赋值为100; 程序再向下执行,ret() 调用test_in()这个函数,把1赋值给number2。  

     其中以下代码就称之为闭包

    def test_in(number2):
        print("--3--")
        print(number+number2)

        装饰器: 高阶函数+内嵌函数+闭包 ==> 装饰器,

        装饰器满足条件:1、不对原代码进行修改;2、不对调用方式进行更改;3、再原功能上实现功能添加

    例1:简单装饰器

    原有代码:

def test():
    print('---test---')

test()

    此时使用装饰器对代码进行装饰,且不更改原有的代码及调用方式

def make1(func):
    def inner():
        print("--装饰test---")
        func()
    return inner

@make1
def test():
    print('---test---')

test()

    运行结果:

--装饰test---
---test---

    代码讲解: 程序中@make1 即为装饰器,使用@make1对test()这个函数进行装饰(需要对某个函数进行装饰,只需在函数上方使用@函数名即可),@make1 等价于,test = make1(test)。 程序从上往下执行,先定义make1函数,再定义test函数,随后运行@make1即(test = make1(test)),此时调用make1()通过return返回inner函数的内存地址,且把test函数的内存地址传递给func,再次把结果赋值给test这个变量,这个时候的test相当于是一个新的内存地址;再由test()来进行调用。且装饰器是执行到@时就已进行装饰,而不是等到调用时才执行

    

    例2:有返回值的装饰器

def test2(func):
    print("---test2---")
    def test3():
        message1 = func()
        return  message1
    return test3

@test2
def test1():
    print("---test1---")
    return "Test_Rerurn"

message2 = test1()
print(message2)

    运行结果:

---test2---
---test1---
Test_Rerurn

    代码讲解:通过@test2装饰器对test1进行装饰,运行test2()这个函数,打印“--test2--”把test1内存地址赋值给func,再通过return返回test3函数内存地址并赋值给新变量test1,再次通过test1()调用test3(),运行函数里的func(),执行最原始的test1代码,打印“--test1--”并把返回的“TestReturn”赋值给message1,再次返回message1, 再把返回的结果用message2保存,最后再打印出来。

    例3:多个装饰器

def makeBold(fn):
    def wrapped():
        print("----1---")
        return "<b>" + fn() + "</b>"
    return wrapped

def makeItalic(fn):
    def wrapped():
        print("----2---")
        return "<i>" + fn() + "</i>"
    return wrapped

@makeBold
@makeItalic
def test3():
    print("----3---")
    return "hello world-3"

ret = test3()
print(ret)

    运行结果:

----1---
----2---
----3---
<b><i>hello world-3</i></b>

    代码讲解: 在装饰器中可以使用多个装饰器,程序从上往下依次执行。


    例4:带参数的装饰器

def func(functionName):
    print("---func---1---")
    def func_in(*args, **kwargs):
        print("---func_in---1---")
        functionName(*args, **kwargs)
        print("---func_in---2---")

    print("---func---2---")
    return func_in

@func
def test(a, b, c):
    print("----test-a=%d,b=%d,c=%d---"%(a,b,c))


test(11,22,33)

    运行结果:

---func---1---
---func---2---
---func_in---1---
----test-a=11,b=22,c=33---
---func_in---2---

    代码讲解:通过@func装饰器对test进行装饰,将test函数的内存地址传递给functionName,返回func_in的内存地址返回,用新变量test保存,再来执行test(11,22,33),此时会调用func_in这个函数, 为了保证函数通用行,test传递的形参,fun_in需要用不定长参数来保存,其中functionName()执行时,也需要携带不定长参数。

    例5:装饰器实用:

import time
user,passwd = 'alex','abc123'
def auth(auth_type):
    #print("auth func:",auth_type)
    def outer_wrapper(func):
        def wrapper(*args, **kwargs):
            #print("wrapper func args:", *args, **kwargs)
            if auth_type == "local":
                username = input("Username:").strip()
                password = input("Password:").strip()
                if user == username and passwd == password:
                    print("\033[32;1mUser has passed authentication\033[0m")
                    res = func(*args, **kwargs)  
                    print("---after authenticaion ")
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            elif auth_type == "ldap":
                print("PASS")

        return wrapper
    return outer_wrapper

def index():
    print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
    print("welcome to home  page")
    return "from home"

@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs  page")

index()
home() 
bbs()

    运行结果:

welcome to index page
Username:alex
Password:abc123
User has passed authentication
welcome to home  page
PASS
    大概讲解:该例子主体为有index函数、home函数、bbs函数, 先需要对home已及bbs进行访问验证,而验证的方式有两种,一种为local本地验证,一种为ldap验证,通过装饰器来对函数进行装饰,并且通过装饰器传递的值不同,用来进行验证方式的判断

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值