• python迭代器、生成器、装饰器之装饰器


    装饰器。。。。。。

    定义:本质是函数,为其他函数添加附加功能

    原则: 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
    def foo():
        time.sleep(3)
        print('from foo')
    
    
    foo()
    

    高阶函数。。。。。下面的例子中foo就是属于一个高阶函数。

    '''
    高阶函数:
        1、函数接收的参数是一个函数名
        2、函数的返回值是一个函数名
        只要满足其中一个就属于高阶函数
    '''
    
    
    def fun():
        print("from fun")
    
    
    def foo(fun1):
        fun1()
    
    
    foo(fun)

     返回值是函数名的高阶函数

    def fun():
        print("from fun")
    
    
    def foo(fun1):
        return fun1
    
    
    foo(fun)()

    函数嵌套。。。。。。通过下面的例子,可以看出,函数内可以套函数,而函数也是一个变量,

    通过locals()可以看到。

    '''
    函数嵌套
    '''
    
    
    def fun1():
        print("from fun1")
    
        def fun2():
            print("from fun2")
    
        print(locals())
    
    
    fun1()
    # 运行结果
    #from fun1
    #{'fun2': <function fun1.<locals>.fun2 at 0x000002A2C4D4AD90>}
    

    闭包闭包,一个函数一个包。。。主要还是作用域,请看https://blog.csdn.net/June_King/article/details/87090970

    重点来了。装饰器。。。。。。

    # 简单的装饰器例子
    def timer(func):
        def wrapper():
            func()
    
        return wrapper
    
    
    def test():
        time.sleep(3)
        print("test函数执行完毕")
    
    
    res = timer(test)
    res()

    这是不对的,前面说过,装饰器不能修改被装饰函数的源代码,不能修改被装饰函数的调用方式。

    这里调用时,修改了调用的方式。。。

    那这样呢?

    test = timer(test)
    test()

    看着是没有修改调用方式,但是每次调用时都会重新赋值。。。这样不合理

    那应该怎么做?下面这样写,仅仅是在函数调用之前加上@装饰器名字即可

    @timer
    test()

    看下面的例子,看看都打印了什么。

    def timer(func):
        def wrapper():
            func()
    
        return wrapper
    
    @timer
    def test():
        time.sleep(2)
        print("test函数执行完毕")
        return "test()的返回结果"
    
    
    res = test()
    print(res)

    可以发现,我们并没有得到test()函数的返回值,如果想要得到被装饰函数的返回值,需要这样写

    def timer(func):
        def wrapper():
            res = func()
            return res
        return wrapper

    在装饰器中通过变量来接收被装饰函数的返回值,然后利用return返回。这样一个带有返回值的装饰器就书写完成了。

    这些还远远不够,有时候我们被修饰的函数还需要传入一些参数

    def timer(func):
        def wrapper(name, age):
            res = func(name, age)
            return res
    
        return wrapper
    
    
    @timer
    def test(name, age):
        time.sleep(2)
        print("name:%s,age:%d," % (name, age))
        print("test函数执行完毕")
        return "test()的返回结果"
    
    
    res = test('june', 18)
    print(res)

    上面的例子虽然可以传递参数,但依然存在不足,当test()的参数变化时,上面的例子就不能用了,需要对装饰器进行改进

    def timer(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs)
            return res
    
        return wrapper

    上面的这个例子可以实现无论被修饰函数的参数如何让改变,都能够接收。关于*args,**kwargs可以参考https://blog.csdn.net/June_King/article/details/87085052

    好了,目前为止我们写的装饰器可以传入参数,也可以拥有返回值了,那么如果我们的装饰器还需要参数的话,那。。。。

    def auth(filed):
        print(filed)
    
        def fun1(fun):
    
            def fun2(*args, **kwargs):
                fun(*args, **kwargs)
    
            return fun2
    
        return fun1
    
    
    @auth("我是装饰器的参数")
    def foo():
        print("from foo")
    
    
    foo()

    在原来的基础上再加一层函数。。。

    小结,不修改原函数代码,不修改原函数的调用方式。

  • 相关阅读:
    GetHub下载不成功
    Cache 判断Ip几分钟内攻击次数
    .net 通过Url获取站点json数据
    Linq 读取Xml 数据
    ef Linq 自定义字段列表
    面试的心得
    触发器--单独字段变化另一个字段也变化
    Ajax跨域 取值 Jsonp的定义注意事项
    asp.net里,各种下载方式汇总
    c# 获取硬件信息
  • 原文地址:https://www.cnblogs.com/June-King/p/10596205.html
Copyright © 2020-2023  润新知