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

    装饰器是什么

    用来修饰别的函数的函数就可以称之为装饰器
    这种函数的参数一般就是另外一个函数
    也就是说,调用这种函数,需要给这种函数传参,且参数是函数

    @语法糖

    @语法糖一般用来表示装饰器函数
    不用@也可以达到装饰函数的目的,下面会有演示

    函数嵌套

    在一个函数中定义另外一个函数

    def f1(arg="aaa"):
          def f2():
    	       return "hello"
    	  def f3():
    	      return "hi"
    	  def f4():
    	     return "haha"
          
    	 print f2()
    	 print f3()
    	 print f4()
    

    这个f1函数有默认参数,所以可以不传参执行
    执行f1()调用之后
    执行结果如下:
    hello
    hi
    haha

    在函数里返回函数
    def hi(arg="aaa"):
        def greet():
            return "bbb"
    
        def welcome():
            return "ccc"
    
        if arg == "aaa":
            return greet
        else:
            return welcome
    
    a = hi()
    print(a)
    print (a())
    

    这里同样使用了默认参数,则a = hi() 会命中 if arg == "aaa"这个逻辑
    返回greet,注意在这里,greet是函数,不是字符串,如果是返回字符串,则要返回的是 return "greet"这种
    上面这段代码执行的结果是
    <function greet at 0x7f75f7a0e1b8>
    bbb

    为什么是这样的执行结果呢?第一个地方 print(a),打印的是a = hi()的结果
    我们可以看到,hi()的返回结果都是在return一个函数,要么是greet函数,要么是welcome函数
    函数就是对应一个地址,所以第一处打印的是这个函数的地址
    第二处做了a的调用,即a(),则打印返回的函数即greet函数执行的结果,即bbb

    将函数作为参数传给另外一个函数
    def hi():
        return "hi"
    
    def hello(func):
        print("before func()")
        print(func())
    
    hello(hi)
    

    执行结果是
    before func()
    hi
    这里把hi这个函数作为参数传给hello函数
    hello函数先打印一句自身的输出before func()
    再执行这个被传入的函数
    我们可以看到,通过装饰器,我们可以在一个函数被调用前干一些需要的事情

    不用@实现装饰器
    def hi(a_func):
    
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    def haha():
        print("I am the function which needs some decoration ")
    
    haha = hi(haha)
    print haha()
    

    运行结果:

    I am doing some boring work before executing a_func()
    I am the function which needs some decoration
    I am doing some boring work after executing a_func()
    None
    这个就是装饰器,起到了用hi函数装饰了haha函数的功能

    那么怎么用@语法糖实现呢
    def hi(a_func):
    
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    @hi
    def haha():
        print("I am the function which needs some decoration ")
    
    haha()
    

    可以看到,装饰器就是用希望装饰别的函数的函数,比如 ,希望用A装饰B
    就在定义B函数的上一行,写上 @A

    def A():
         pass
    	 
    	 
    @A	 
    def B():
        pass
    

    总结:理解就是装饰器其实就是这样一种函数:带参数的,且参数是另外一个函数的函数
    使用装饰器的目的一般是为了在运行时改变函数的一些属性/行为,就可以给这个函数加上装饰器,让装饰器去在这个函数被调用前后,干一些你想做的事情

    wraps干什么的?

    我们修改下上面的代码,多记录一点东西

    def hi(a_func):
    
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    @hi
    def haha():
        print("I am the function which needs some decoration ")
    
    haha()
    print(haha.__name__)
    

    我们的意图是打印haha这个函数的函数名,但实际上打印的是hello
    为什么?
    因为haha这个函数使用装饰器之后,haha的行为部分被装饰器函数改变了
    可以看到,用hi函数装饰了haha之后,返回的是hello函数,那么当我们需要拿到被装饰函数的函数名,还有其他属性的时候怎么做呢?
    使用functools.wraps方法

    from functools import wraps
     def hi(a_func):
       @wraps(a_func)
        def hello():
            print("I am doing some boring work before executing a_func()")
    
            a_func()
    
            print("I am doing some boring work after executing a_func()")
        return hello
    
    @hi
    def haha():
        print("I am the function which needs some decoration ")
    
    haha()
    print(haha.__name__)
    

    执行结果如下:

    I am doing some boring work before executing a_func()
    I am the function which needs some decoration
    I am doing some boring work after executing a_func()
    haha
    正是我们想要的结果
    @wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

    举一个记录日志的例子
    from functools import wraps
    
    def logit(func):
        @wraps(func)
        def with_logging(*args, **kwargs):
            print(func.__name__ + " was called")
            return func(*args, **kwargs)
        return with_logging
    
    @logit
    def addition_func(x):
       """Do some math."""
       return x + x
    
    
    result = addition_func(4)
    # Output: addition_func was called   
    
  • 相关阅读:
    PE文件简介
    hook键盘驱动中的分发函数实现键盘输入数据的拦截
    遍历系统中加载的驱动程序以及通过设备对象指针获取设备对象名称
    如何利用git shell提交代码到github
    驱动开发中的常用操作
    3.1_栈_顺序存储结构(数组形式)
    2.6_链表深入
    2.5_线性表的链式存储结构_双向链表
    2.4_线性表的链式存储结构_单链表具体实现
    2.3_线性表的链式存储结构_单链表
  • 原文地址:https://www.cnblogs.com/haozike/p/python_decorator_summary.html
Copyright © 2011-2022 走看看