美文网首页
python学习绕不过的函数装饰器

python学习绕不过的函数装饰器

作者: 无敌小小坤 | 来源:发表于2019-07-22 22:31 被阅读0次
    • 概念:类似于将函数包裹起来,实现同一功能的函数
    • 功能:在代码运行期间动态增加功能的方式

    一、知识准备

    • 理解python中 *args 和 **kwargs
    # 测试函数
    def test_args_kwargs(arg1,arg2,arg3):
        print("arg1:",arg1)
        print("arg2:",arg2)
        print("arg3P:",arg3)
    # 使用*args
    args = ("two",3,5)
    test_args_kwargs(*args)
    # 使用 **kwargs
    kwargs = {"arg3":5,"arg1":two,"arg2":3}
    test_args_kwargs(**kwargs)
    # 可以同时使用,但应注意顺序
    
    • python 中的函数名称也是对象(一切皆对象)
    def hi(name):
        print("hi! ",name)
    # 使用函数名作为变量
    welcom = hi
    welcom("xiaoming")
    
    • 在函数中定义函数
    def hi(name='wangweiyang'):
        print("now you are in insdie the hi() function")
        # 定义内部函数
        def greet()
            print("now you are in the greet() function")
        def welcome()
            print("now you are in the welcome() function")
    hi()
    # 内部函数在外部是不能直接访问的
    >>> greet() 错误
    
    • 从函数中返回函数
    def hi(name='wangweiyang'):
        def greet():
            return "now you are in the greet() function"
        def welcome():
            return "now you are in the welcome() function"
        if name == "wangweiyang":
            return greet
        else:
            return welcome
    a = hi()
    print(a)
    print(a())
    
    • 将函数作为参数传递给另一个函数
    def hi():
        return "hi!wangweiyang!"
    def doSomethingBeforeHi(func):
        print("Do something before executing hi()")
        print(func())
    doSomethingBeforeHi(hi)
    
    • 创建第一个装饰器
    # 装饰函数
    def a_new_decorator(a_func):
        def wrapTheFunction():
            print("Do some work before executing a_func()")
            a_func()
            print("Do some work after executing a_func()")
        return wrapTheFunction
    # 被装饰的函数
    def a_function_requiring_decoration():
        print("The function which needs some decoration to remove or add something")
    # 装饰过程    
    a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
    # 装饰结果
    a_function_requiring_decoration()
    
    • 闭包

    二、创建装饰器

    • 使用@符号:本质上就是装饰过程(简化与统一)
    # 装饰函数
    def a_new_decorator(a_func):
        def wrapTheFunction():
            print("Do some work before executing a_func()")
            a_func()
            print("Do some work after executing a_func()")
        return wrapTheFunction
    # 使用@符号进行装饰
    @a_new_decorator
    def a_function_requiring_decoration():
        """
        Please decorate me!
        """
        print("The function which needs some decoration to remove or add something")
    # 装饰结果
    a_function_requiring_decoration()   
    
    • 使用装饰器会覆盖掉(重写)原函数本身的一些函数属性
    # 输出函数本身名称
    print(a_function_requiring_decoration.__name__)
    # output:wrapTheFuction()
    print(a_function_requiring_decoration.__doc__)
    # output:None
    
    • 使用functools.wraps来解决函数属性的问题
    # 引入wraps
    from functools import wraps
    # 装饰函数
    def a_new_decorator(a_func):
        @wraps(a_func)
        # 使用wraps
        def wrapTheFunction():
            print("Do some work before executing a_func()")
            a_func()
            print("Do some work after executing a_func()")
        return wrapTheFunction
    # 使用@符号进行装饰
    @a_new_decorator
    def a_function_requiring_decoration():
        """
        Please decorate me!
        """
        print("The function which needs some decoration to remove or add something")
    # 装饰结果
    a_function_requiring_decoration() 
    print(a_function_requiring_decoration.__name__)
    # output: a_function_requiring_decoration
    

    三、装饰器的使用场景

    • 授权(Authorization)-Django与Flask框架
    from functools import wraps
    def requires_auth(f):
        @wraps(f)
        def decorated(*args,**kwargs):
            auth = request.authorization
            if not auth or not check_auth(auth.username,auth.password):
                authenticate()
            return f(*args,**kwargs)
        return decorated
    
    • 日志(Logging)
    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
    

    四、装饰器进阶

    • 在函数中嵌入装饰器(可以接收函数的装饰器)
    from functools import wraps
    def logit(logfile="out.log"):
        def logging_decorator(func):
            @wraps(func)
            def wrapped_function(*args,**kwargs):
                log_string = func.__name__ + "was called"
                print(log_string)
                # 打开logfile,并写入内容
                with open(logfile,"a") as opend_file:
                    # 将日志写入指定的logfile
                    opend_file.write(log_string + "\n")
                return func(*args,**kwargs)
            return wrapped_function
        return logging_decorator
    @logit
    def myfunc1():
        pass
    myfunc1()
    @logit(logfile='func2.log')
    def myfunc2():
        pass
    myfunc2
    
    • 装饰器类
    from functools import wraps
    class logit(object):
        def __init__(self,logfile='out.log'):
            self.logfile = logfile
        def __call__(self,func):
            @wraps(func)
            def wrapper_function(*args,**kwargs):
                log_string = func.__name__ + "was called"
                print(log_string)
                # 打开logfile并写入
                with open(self.logfile,'a') as opend_file:
                    # 将日志写入指定的文件
                    opened_file.write(log_string + '\n')
                # 发送一个通知
                self.notify()
                return func(*args,**kwargs)
            return wrappend_function
        def notify(self):
            # logit只打开日志
            pass
    @logit()
    def myfunc1():
        pass
    class email_logit(logit):
        """
        一个logit的实现版本,可以在函数调用时发送email给管理员
        """
        def __init__(self,email="xxx@qq.com",*args,**kwargs):
            self.email = email
            super(email_logit,self).__init__(*args,**kwargs)
        def notify(self):
            # 发送一封邮件给管理员
            pass
    

    相关文章

      网友评论

          本文标题:python学习绕不过的函数装饰器

          本文链接:https://www.haomeiwen.com/subject/segglctx.html