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
    '''
    

     

  • 相关阅读:
    leetcode 416. Partition Equal Subset Sum
    leetcode 696. Count Binary Substrings
    leetcode 74. Search a 2D Matrix
    leetcode 199. Binary Tree Right Side View
    leetcode 43. Multiply Strings
    leetcode 695. Max Area of Island
    leetcode 257. Binary Tree Paths
    leetcode 694. Number of Distinct Islands
    ros使用时的注意事项&技巧2
    ros使用时的注意事项&技巧
  • 原文地址:https://www.cnblogs.com/jmwm/p/9759251.html
Copyright © 2011-2022 走看看