py10 装饰器

五 装饰器

装饰器就是闭包函数的一种应用场景

一 为何要用装饰器

#开放封闭原则:对修改封闭,对扩展开放

二 什么是装饰器

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

三 装饰器的使用

函数不固定参数,装饰器的使用

import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper

@timmer # 相当于 foo = timmer(foo)
def foo():
time.sleep(2)
print('from foo')

@timmer # 相当于 foo = timmer(foo)
def foo1(name):
time.sleep(2)
print('from foo', name)


foo()
foo1('weilianxin')

上述的foo经过装饰器装饰后,foo已经相当于wrapper,foo1亦是如此,所以运行foo和foo1相当于运行wrapper,传参也是向wrapper传参。

 foo1给timmer(func):,name给了wrapper(*args,**kwargs):,然后传给res=func(*args,**kwargs),原foo1若有返回值,则传给res

有参装饰器的使用

def auth(auth_type):
    print("auth func:", auth_type)

    def outer_wrapper(func):
        print('123456')
        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)  # from home
                    print("---after authenticaion ")
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            elif auth_type == "ldap":
                print("搞毛线ldap,不会。。。。")
        return wrapper
    return outer_wrapper



@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")


print('===============',home())  # wrapper()
# bbs()

auth_type="local"会传参给auth(auth_type),home传给outer_wrapper(func),home若有参数则类似上一种,继续往里传

注意:

装饰器中函数上面的@fun在解释器走到函数定义时会运行代码,运行外层函数:

import time


def timer(func):
    print('adfadsfasf')
    def deco(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print("time is", end-start)
    return deco


@timer  # test1 = timer(test1)
def test1():
    time.sleep(3)
    print("it is test1")


@timer
def test2():
    time.sleep(3)
    print("it is test2")


@timer
def test3(name):
    time.sleep(1)
    print("it is test3", name)
# test1 = timer(test1)
# test1()
# test2()
# test3("weilianxin")
pass

在调用语句被注释后,依然执行了@timmer,执行了外层函数,输出了三行
adfadsfasf
adfadsfasf
adfadsfasf

四 装饰器语法

复制代码
被装饰函数的正上方,单独一行
        @deco1
        @deco2
        @deco3
        def foo():
            pass

        foo=deco1(deco2(deco3(foo)))
复制代码

五 装饰器补充:wraps

Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展。但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题。Python 通过 functool.wraps 为我们解决了这个问题:在编写装饰器时,在实现前加入 @functools.wraps(func) 可以保证装饰器不会对被装饰函数造成影响。比如,在 Flask 中,我们要自己重写 login_required 装饰器,但不想影响被装饰器装饰的方法,则 login_required 装饰器本身可以写成下面的样子:

def login_required_(func):
    @wraps(func)
    def decorated_view(*args, **kwargs):
        if current_app.login_manager._login_disabled:
            return func(*args, **kwargs)
        elif not current_user.is_authenticated:
            # return current_app.login_manager.unauthorized()
            return redirect(url_for("login.loginPage", next=request.url))
        return func(*args, **kwargs)

    return decorated_view
复制代码
from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)
复制代码

猜你喜欢

转载自www.cnblogs.com/wlx97e6/p/9385082.html
今日推荐