欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python中为其他函数添加额外功能,而不修改源代码的方式-------装饰器的使用讲解及代码示例(类似于java的装饰设计模式)

程序员文章站 2024-03-26 11:20:05
...

讲解内容及代码都在下面

#Filename:decorator.py
#场景:本身一套程序已经有了自己本身的一系列函数,但是,现在这些函数的功能有限,
#想要增加一些额外的功能,但是,如果要是修改原代码的话,可能会产生一系列的连带
#错误,所以,就产生了装饰器的概念。

#装饰器:本质就是一个函数,装饰其他的函数,为其他的函数添加附加的功能。

#原则:不修改被装饰函数的原代码以及调用方式,类似于java的装饰设计模式

#要想学会装饰器必须先知道两个概念,一个是高阶函数,另一个是嵌套函数
#高阶函数:把一个函数名作为实参传递给另一个函数,返回值是函数名
#嵌套函数:就是一个函数嵌套一个函数,需要注意的是,嵌套必须是def嵌套def,比如
#def test:
#   test()
#上面这个例子就不是嵌套函数,只是函数的调用而已

#装饰器=高阶函数+嵌套函数
#
#步骤:
#1.创建一个装饰器,也就是函数timer,把func作为参数传进去,代表任意的函数。
#2.直接在装饰器里面嵌套一个函数,由于可能传递若干个参数,也可能不传参数,
#所以我们用*args,**kwargs代替。
#3.在嵌套函数里面调用原来的老函数即func(*args,**kwargs),并写入新的逻辑。
#4.返回嵌套函数,到此为止,装饰器里面只是返回了一个函数,并没有进行调用。
#5.在原来的函数上面写上@timer,代表test1=timer(test1),这句话的意思是将原来
#的函数传到装饰器当中,返回的deco就等于了test1。
#6.调用test1(),由于deco等于test1,所以test1()就相当于deco(),也就自然
#的调用了新的和旧的逻辑。(带参数的test2同理)

#到此为止,我们也就达成了效果,不修改被装饰函数的原代码以及调用方式
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("函数的运行时间为:" ,stop_time-start_time)
        #获取时间差
    return deco
@timer  #test1=timer(test1)
def test1():
    time.sleep(1)#让时间等待一秒
    print('老函数1')

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

结果:

老函数1
函数的运行时间为: 1.0200014114379883
test2: Rain 22
函数的运行时间为: 0.029999971389770508 

下面的例子是装饰器的加强功能

#不用特别看懂具体的处理逻辑

#现在来思考两个问题:
#第一个:如果原来的函数有返回值该怎么办
#第二个:如果两个老函数需要加以区分该怎么办

#第一个的解决方式:这里的home()返回了内容,所以我们需要在代码中改一些,即
#res = func(*args, **kwargs)  # from home
#return res
#也就是在嵌套函数调用中将老函数返回的值赋给res,再返回res
#最后再调用print(home()) #wrapper(),将它打印出来即可。

#第二个的解决方式:
#首先我们在老函数的上边的@auth(auth_type="ldap")加了一个参数,加以区分
#然后,我们在装饰类中又多加了一层
#def auth(auth_type):
#   print("auth func:",auth_type)
#   def outer_wrapper(func):
#第一层的参数是加以区分的内容
#第二层的参数是需要传递进来的函数
#记得要在后面同样的返回这个outer_wrapper函数
########################
import time
user,passwd = '1','2'
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)  # 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

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()

结果:

auth func: local
auth func: ldap
welcome to index page
wrapper func args:
Username:1
Password:2
[32;1mUser has passed authentication[0m
welcome to home  page
---after authenticaion 
from home
wrapper func args:
搞毛线ldap,不会。。。。