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

    现有如下函数:

    def fun1():
        print('...fun1()...')
    
    def fun2():
        print('...fun2()...')
    
    #调用函数
    fun1()
    fun2()
    

     

    需求:需要给以上两个函数添加记录日志功能

    方法一:函数调用

    def logging():
        print('...logging...')
    
    def fun1():
        print('...fun1()...')
        logging()
    
    def fun2():
        print('...fun2()...')
        logging()
    
    #调用函数
    fun1()
    fun2()
    

     分析:上面这种方式适合少量函数调用,如果有n个地方需要调用logging()函数,那么得手动调用n次,比较麻烦,而且在fun1()中调用loggin()也相当于修改了fun1()的内容。

     

    方法二:高阶函数(函数名作为参数传递给另一个函数)

    def logging(fun):
        fun()
        print('...logging...')
    
    def fun1():
        print('...fun1()...')
    
    
    def fun2():
        print('...fun2()...')
    
    
    #调用函数
    logging(fun1)
    logging(fun2)
    

     分析:该方法是高阶函数的用法,将函数名当做参数传递给另一个函数,优点是没有修改源代码,缺点是该方法修改了调用的方式。

     

    方法三:高阶函数(返回值中包含函数名)

    def logging(fun):
        print('...logging...')
        return fun
    
    
    def fun1():
        print('...fun1()...')
    
    
    def fun2():
        print('...fun2()...')
    
    
    #调用函数
    fun1 = logging(fun1)
    fun2 = logging(fun2)
    fun1()
    fun2()
    

     分析:该方法的优点是没有改变原有函数的调用方式,但是改变的原有输出顺序。

     

    方法四:嵌套函数

    def logging(fun):
        def dec(fun):
            return fun()
        dec(fun)
        print('...logging...')
    
    
    def fun1():
        print('...fun1()...')
    
    
    def fun2():
        print('...fun2()...')
    
    
    #调用函数
    logging(fun1)
    logging(fun2)
    

     分析:该方法优点是没有修改源代码,但是调用方式改变了。

     

    总结:

    如果需要不修改源代码、不修改调用方式,则需要使用高阶函数+嵌套函数一起,由此引入了装饰器的概念。

     

     

    装饰器

    定义:本质是函数(装饰其他函数),就是为其他函数添加附加功能。

    原则:1.不能修改被装饰函数的源代码

       2.不能修改被装饰函数的调用方式

     

    装饰器知识储备:

    1.函数即“变量”

    2.高阶函数
      a:函数名作为实参传给另一个函数(在不修改源代码的情况下为其新增功能)
      b:返回值中包含函数名(不修改函数的调用方式)

    3.嵌套函数

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

     

    使用高阶函数+嵌套函数修改上面需求:

    def logging(fun):
        def dec():
            fun()
            print('...logging...')
        return dec
    
    
    def fun1():
        print('...fun1()...')
    
    
    def fun2():
        print('...fun2()...')
    
    
    #调用函数
    fun1 = logging(fun1)
    fun2 = logging(fun2)
    fun1()
    fun2()
    

     

    装饰器语法糖:即在函数前使用@函数名

    使用语法糖修改以上代码:

    def logging(fun):
        def dec():
            fun()
            print('...logging...')
        return dec
    
    @logging
    def fun1():
        print('...fun1()...')
    
    @logging
    def fun2():
        print('...fun2()...')
    
    
    #调用函数
    fun1()
    fun2()
    

    如上案例中的@logging可以理解为:fun1 = logging(fun1)

     

    案例:无参装饰器与有参装饰器

    无参装饰器

    def fun(func):
        def dec():
            func()
            print('...新增功能...')
        return dec
    
    @fun
    def foo():
        print('...test1()...')
    
    foo()
    

     

    def fun(func):
        def dec(x,y):
            func(x,y)
            print('...新增功能...')
        return dec
    
    @fun
    def foo(x,y):
        print(x+y)
        print('...test1()...')
    
    
    
    foo(5,3)
    

     

    有参装饰器:

    def out_fun(m,n):
        def in_fun(fun):
            def dec(x,y):
                fun(x,y)
                print('...新功能...')
                print("m*n=%s"%(m*n))
            return dec
        return in_fun
    
    
    @out_fun(2,6)
    def foo(x,y):
        print(x+y)
        print('...test1()...')
    
    
    
    foo(5,3)    # out_fun(2,6)(foo)(5,3)
    
    '''
    8
    ...test1()...
    ...新功能...
    m*n=12
    '''
    

     

  • 相关阅读:
    漂亮的自适应宽度的多色彩CSS图片按钮
    Qt中设置widget背景颜色/图片的注意事项(使用样式表 setStyleSheet())
    QT的父子Widget之间消息的传递(如果子类没有accept或ignore该事件,则该事件会被传递给其父亲——Qlabel与QPushButton的处理就不一样)
    QT内置的ICON资源
    QT事件过滤器(QT事件处理的5个层次:自己覆盖或过滤,父窗口过滤,Application过滤与通知)
    QMetaObject感觉跟Delphi的类之类有一拼,好好学一下
    POJ 1013 小水题 暴力模拟
    WMDestroy函数调用inherited,难道是为了调用子类覆盖函数?还有这样调用的?
    技术资深、还关注市场的几率较高
    有感,懂市场比懂产品重要,懂产品比懂技术重要——想起凡客诚品和YY语音了
  • 原文地址:https://www.cnblogs.com/jmwm/p/9759251.html
Copyright © 2011-2022 走看看