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

  • 概念:类似于将函数包裹起来,实现同一功能的函数
  • 功能:在代码运行期间动态增加功能的方式

一、知识准备

  • 理解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="[email protected]",*args,**kwargs):
        self.email = email
        super(email_logit,self).__init__(*args,**kwargs)
    def notify(self):
        # 发送一封邮件给管理员
        pass

你可能感兴趣的:(python学习绕不过的函数装饰器)