装饰器

Pyhon装饰器

标签(空格分隔): 进阶


装饰器:本质是函数,(装饰其他函数)就是为其它函数提供附加功能

原则
1、不能修改被装饰函数的源代码
2、不能修改被装饰函数的调用方式

#下面定义了一个装饰器应用的例子。timmer函数作为装饰器,来给test1()函数增加了一个打印函数运行时间的功能
import time
def timmer(func):
    def warpper(*args,**kwargs):
        start_time=time.time()
        func()
        stop_time=time.time()
        print('the func run time is %s' %(stop_time-start_time))
    return warpper

@timmer
def test1():
    time.sleep(3)
    print('in the test1')

test1()

实现装饰器知识储备:

1、函数即“变量”
2、高阶函数
a)把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
b)返回值中包含函数名 (不修改函数的调用方式)
3、嵌套函数

高阶函数+嵌套函数=》装饰器

1、函数即变量
定义了一个函数就相当于把函数体赋值给了函数名

def test()
    pass
#上面的test()函数就相当于: test = '函数体'

看以下三种调用foo()函数的结构,思考
1、哪种能正常运行
2、为什么

#示范一:
def bar():
    print('in the bar')
def foo():
    print('in the foo')
    bar()
foo()

#示范二:
def foo():
    print('in the foo')
    bar()
def bar():
    print('in the bar')
foo()

#示范三:
def foo():
    print('in the foo')
    bar()
foo()
def bar():
    print('in the bar')

2、高阶函数
a)把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)

##下面这段代码把bar做为实参传给函数test
def bar():
    print ("in the bar")
def test(func):
    print (func)
    func()

test(bar)
##下面这段代码通过把函数bar做为实参传给函数test,在不修改函数bar源代码的情况下,增加了计算了函数bar的运行时间的功能
import time
def bar():
    time.sleep(3)
    print('in the bar')

def test(func):
    start_time=time.time()
    func()    #run bar
    stop_time=time.time()
    print("the func run time is %s" %(stop_time-start_time))

test(bar)

b)返回值中包含函数名 (不修改函数的调用方式)

##下面这段代码仍然是把函数bar做为实参传给函数test。然后先调用高阶函数test实现了一些附加功能(计算函数bar的运行时间),再返回函数bar的地址。最终通过增加代码“bar = test()”实现既执行了函数test,又   
import time
def bar():
    time.sleep(3)
    print('in the bar')
def test(func):
    print(func)
    return func
    
bar=test(bar)
bar()  #run bar

3、嵌套函数
定义:在一个函数的函数体内用def去声明一个新的函数(不是调用)

def foo():
    print('in the foo')
    def bar():
        print('in the bar')
    bar()
foo()

装饰器

通过前面的知识储备,下面可以开始学些装饰器了。

##下面代码通过高阶函数+嵌套函数的功能实现了既不修改函数test代码,又不修改函数test调用方式,而增加了打印函数test运行时间的功能

import time
def timer(func): #timer(test)  func=test
    def deco():
        start_time=time.time()
        func()   #run test()
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))
    return deco

def test():
    time.sleep(1)
    print('in the test')

test = timer(test)
test()

利用语法糖来实现上述功能

import time
def timer(func): #timer(test)  func=test
    def deco():
        start_time=time.time()
        func()   #run test()
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))
    return deco

@timer # 等于 test = timer(test)
def test():
    time.sleep(1)
    print('in the test')

test()

装饰带参数的函数

上面代码已经实现了装饰器的功能,没修改被装饰函数的源代码也没修改调用方式,但是却只能装饰简单的函数,如果被装饰函数带有参数就无法实现了。下面看怎么装饰带参数的函数。

##利用可变参数来装饰带有任何数量参数的函数

import time
def timer(func): #timer(test1)  func=test1
    def deco(*args,**kwargs):
        start_time=time.time()
        func(*args,**kwargs)   #run test1()
        stop_time = time.time()
        print("the func run time  is %s" %(stop_time-start_time))
    return deco
@timer  #test1=timer(test1)
def test1():
    time.sleep(1)
    print('in the test1')

@timer # test2 = timer(test2)  = deco  test2(name) =deco(name)
def test2(name,age):
    print("test2:",name,age)

test1()
test2("alex",22)

装饰带返回值的函数

上节通过可变参数来实现装饰带任意参数的函数。但是只能装饰不带返回值的函数,仍有一定的局限性,下面看怎么装饰带返回值的函数。

##下面这段代码装饰了带返回值的函数home,但是打印函数运行结果时,却未能将返回值打印出来,思考下为什么,怎样才能得到返回值

user,passwd = 'alex','abc123'
def auth(func):
    def wrapper(*args, **kwargs):
        username = input("Username:").strip()
        password = input("Password:").strip()
        if user == username and passwd == password:
            print("33[32;1mUser has passed authentication33[0m")
            func(*args,**kwargs)
        else:
            exit("33[31;1mInvalid username or password33[0m")
    return wrapper

@auth
def home():
    print("welcome to home  page")
    return "from home"

print (home())
##下面这段代码解决了上述问题

user,passwd = 'alex','abc123'
def auth(func):
    def wrapper(*args, **kwargs):
        username = input("Username:").strip()
        password = input("Password:").strip()
        if user == username and passwd == password:
            print("33[32;1mUser has passed authentication33[0m")
            res = func(*args, **kwargs)
            #此处也可直接用 return (func (*args, **kwargs))
            print("---after authenticaion ")
            return res
        else:
            exit("33[31;1mInvalid username or password33[0m")
    return wrapper

@auth
def home():
    print("welcome to home  page")
    return "from home"

print (home())

修饰符带参数的装饰器

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("33[32;1mUser has passed authentication33[0m")
                    res = func(*args, **kwargs)  # from home
                    print("---after authenticaion ")
                    return res
                else:
                    exit("33[31;1mInvalid username or password33[0m")
            elif auth_type == "ldap":
                print("搞毛线ldap,不会。。。。")

        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()
print(home()) #wrapper()
bbs()
原文地址:https://www.cnblogs.com/sorui/p/8663488.html