zoukankan      html  css  js  c++  java
  • python装饰器

    基于开放封闭的原则,对现有的函数想要扩展新功能,则不推荐对源码进行修改,所以装饰器就是为了扩展函数功能所用。

    #原函数

    def foo():
        print("foo...")
        time.sleep(2)

    #现在需要添加的功能是:为函数计时

    #如果在原函数进行修改,则为

    import time
    def foo():
        start = time.time()
        print("foo...")
        time.sleep(2)
        end = time.time()
        print("spend %s" %(end - start))
    foo()
    
    ########
    foo...
    spend 2.0001144409179688

    #但是如果有成千上万的函数,逐个修改的工程量极大,所以可以修改为

    import time
    def foo():
        print("foo...")
        time.sleep(2)
    
    def show_time(f):
        start = time.time()
        f()
        end = time.time()
        print("spend %s" %(end - start))
    
    show_time(foo)

    #通过另外定义一个函数,将原函数传入,这样对于每个函数则不用重新定义,只需要再传入即可

    #但是,现在使用原函数时,不再是使用原函数名来调用,这样在生产环境中会有较大影响

    #所以需要使函数调用仍为之前的,但功能是扩展的

    def show_time(f):
        def inner():
            start=time.time()
            f()
            end=time.time()
            print("spend %s" %(end-start))
        return inner
    foo=show_time(foo)
    foo()
    
    ########
    foo...
    spend 2.0001142024993896

    #通过返回一个扩展后的函数给源函数接收,这样就可调用原有的函数名,还扩展了功能

    #在python中,还对装饰器进行了一个优雅的设置

    @show_time

    #这个为python的一个语法糖,起作用等同于foo=show_time(foo),在原函数前添加此句即实现了功能扩展

    #小结:

    1.为了实现扩展功能,需要重新定义一个装饰器函数,在装饰器中有一个内部函数inner主要用于功能扩展,且在最后也需要返回inner函数供原函数接收

    2.在装饰器中,使用了高阶函数和闭包的概念。其中传入原函数和返回inner函数则是高阶函数的定义,而inner函数块和inner函数中调用传入的原函数方法则是闭包的概念

    3.调用装饰器函数,只需要在原函数前加 @装饰器函数名  即可

    4.装饰器的实际原理,@语法糖的作用,同下图所示

    #以上仅是装饰器的基础使用

    #如果原函数需要传入参数,则需要在装饰器的内部函数inner时定义

    import time
    def show_time(f):
        def inner(*a,**b):
            start = time.time()
            f(*a,**b)
            end = time.time()
            print("spend %s" %(end - start))
        return inner
    
    @show_time
    def add(*x,**y):
        sums = 0
        for i in x:
            sums += i
        print(sums)
        time.sleep(1)
    
    add(1,5,6,8)
    
    ########
    20
    spend 1.0000574588775635

    #如果是装饰器需要传入参数,则需要再原装饰器外部再定义一层函数,以便传入参数

    import time
    def logger(flag=''):
        def show_time(f):
            def inner():
                start = time.time()
                f()
                end = time.time()
                print("spend %s" %(end - start))
                if flag=='true':
                    print("logs...")
            return inner
        return show_time
    
    @logger('true')
    def foo():
        print("foo...")
        time.sleep(2)
    foo()
    
    ########
    foo...
    spend 2.0001144409179688
    logs...

    #总结:

    1.如果是原函数有参数传入,则在装饰器中的内部函数inner也需要有相同的形参定义

    2.如果是装饰器函数需要参数传入,则需要在装饰器函数外部再添加一层函数,以传入参数给装饰器函数使用,且调用时使用的是外层函数而不再是原装饰器函数

  • 相关阅读:
    图片懒加载原生写法。
    ES6新声明
    下拉刷新上拉加载
    angular动画
    angular路由切换后 轮播以及iscrollJs失效的问题
    ui-route多级嵌套时的默认显示。
    iscroll.js的基本布局
    angular ng-route和ui-route
    require.js JQ
    Cookie&Session
  • 原文地址:https://www.cnblogs.com/jianbonet/p/8650080.html
Copyright © 2011-2022 走看看