• Python--装饰器


    装饰器的应用场景,较为经典的有插入日志、性能测试、事务处理等。 上代码:

    def foo():
        print('foo')
    

     此段代码,如果我们想在不改变原有功能的基础上添加新功能,可以这样做:

    def foo():
        print('foo')
    
    def wrapper(func):
        def inner():
            print('before')
            func()
            print('after')
        return inner
    
    
    foo=wrapper(foo)
    foo()

    打印结果:
    before
    foo
    after

     Python提供了一个语法糖来降低字符输入量。

    def wrapper(func):
        def inner():
            print('before')
            func()
            print('after')
        return inner
    
    @wrapper    #wrapper=wrapper(foo)
    def foo():
        print('foo')
    
    foo()

    打印结果:
    before
    foo
    after

    让我们来关注一下@wrapper的写法,在foo函数定义上加上这一行与另外写foo = wrapper(foo)完全等价,@并没有另外的魔力。

    除了字符输入少了一些,还有一个额外的好处:这样看上去更有装饰器的感觉。 这样还不能满足我们的需求,我们想给foo函数传参数的话,如何处理?

    上代码:

    def wrapper(func):
        def inner(sth):
            print('before')
            func(sth)
            print('after')
        return inner
    
    @wrapper    #wrapper=wrapper(foo)
    def foo(sth):
        print(sth)
    
    foo('apple')

    打印结果:
    before
    apple
    after

     这个是传一个参数的情况,如果我们想传的参数很多,除了多个位置参数之外,还想要传关键字参数,这个时候怎么办呢? func函数通过*args,**kwargs接收实参即可完美实现!

    def wrapper(func):
        def inner(*args,**kwargs):
            print('before')
            func(*args,**kwargs)
            print('after')
        return inner
    
    @wrapper    #wrapper=wrapper(foo)
    def foo(sth1,sth2,sth3,sth4):
        print(sth1,sth2,sth3,sth4)
    
    foo('apple','orange','banana','lemon')

    打印结果:
    before
    apple orange banana lemon
    after

     进一步,我们的foo函数有时候需要使用到返回值,然后如何处理呢?

    import time
    
    def wrapper(func):
        def inner(*args,**kwargs):
            print('before')
            ret = func(*args,**kwargs)
            print('after')
            print(ret)
            return ret
        return inner
    
    
    @wrapper    #foo=wrapper(foo)
    def foo(arg):
        print(arg)
        return 111
    
    res=foo('apple')
    time.sleep(1)
    print(res)
    
    打印结果:
    before
    apple
    after
    111
    111(1秒后打印)
    

     此外,functools模块提供有装饰器:wraps(wrappedassignedupdated)。

    函数是有几个特殊属性比如函数名,在被装饰后,上例中的函数名foo会变成包装函数的名字inner,我们可以看下例:

    def wrapper(func):
    
        def inner(*args, **kwargs):
            print("before...")
            ret = func(*args, **kwargs)
            print("after/...")
            return ret
        return inner
    
    
    @wrapper   #  foo = wrapper(foo) -->inner
    def foo(sth):
        print(sth)
        return "aaa"
    
    print(foo.__name__)
    
    打印结果:
    inner
    

     这时候wraps就体现了它的作用:它能将装饰过的函数的特殊属性保留。

    import functools
    
    def wrapper(func):
    
        @functools.wraps(func)
        def inner(*args, **kwargs):
            print("before...")
            ret = func(*args, **kwargs)
            print("after/...")
            return ret
        return inner
    
    
    @wrapper   #  foo = wrapper(foo) -->inner
    def foo(sth):
        print(sth)
        return "aaa"
    
    print(foo.__name__)
    
    打印结果:
    foo
    

    关于装饰器,一些有意思的小练习可以拿来做。

    一:编写函数,(函数执行的时间是随机的)
    二:编写装饰器,为函数加上统计时间的功能
    三:编写装饰器,为函数加上认证的功能
    
    四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
    	注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式
    
    五:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
    
    六:为题目五编写装饰器,实现缓存网页内容的功能:
    	具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
    
    七:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
    
  • 相关阅读:
    php文件包含
    微信劫持反弹shell复现
    DNS劫持
    phpstudy后门漏洞复现
    使用远见远控软件控制靶机
    php基础及工具使用
    nmap扫描
    JavaScript创建对象几种形式
    浅拷贝与深拷贝
    原型和原型链
  • 原文地址:https://www.cnblogs.com/metianzing/p/7740114.html
Copyright © 2020-2023  润新知