编程语言
首页 > 编程语言> > 粗浅聊聊Python装饰器

粗浅聊聊Python装饰器

作者:互联网

浅析装饰器

通常情况下,给一个对象添加新功能有三种方式:

一般情况下,优先使用组合,而不是继承。但是装饰器属于第四种,动态的改变对象从而扩展对象的功能。
一般装饰器的应用场景有打印日志,性能测试,事务处理,权限校验;

Python 内置装饰器的工作原理

理解Python装饰器工作原理,首先需要理解闭包这一概念。闭包指的是一个函数嵌套一个函数,内部嵌套的函数调用外部函数的
变量,外部函数返回内嵌函数,这样的结构就是闭包。

装饰器就是闭包的一种应用,但是装饰器参数传递的是函数。

简单的闭包示例:

def add_num(x):
    def sum_num(y):
        return x+y
    return sum_num

add_num5 = add_num(5)
total_num = add_num5(100)
print(total_num)

注解:

装饰器的基本使用

简单计算函数运行时间装饰器示例:

def times_use(func):
    def count_times(*args, **kwargs):
        start = time.time()
        result  = func(*args, **kwargs)
        end = time.time()
        print(end-start)
        return result
    return count_times

@times_use
def test_decorator():
    time.sleep(2)
    print("Test Decorator")
test_decorator()

注解:

根据日志等级打印日志装饰器示例(带参数的装饰器):

def use_logging(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if level == "warn":
                logging.warn("%s is running"% func.__name__)
            result = func(*args, **kwargs)
            print(result) 
            return result
        return wrapper
    return decorator

@use_logging("warn")
def test_decorator():
    print("Test Decorator")
    return "Success"
test_decorator()

计算函数运行时间的类装饰器示例:

class logTime:
    def __init__(self, use_log=False):
        self._use_log = use_log

    def __call__(self, func):

        def _log(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            print(result)
            end_time = time.time()
            if self._use_log:
                print(end_time-start_time)
            return result
        return _log

    
@logTime(True)
def test_decorator():
    time.sleep(2)
    print("Test Decorator")
    return "Success"

functools wraps使用场景

使用装饰器虽然能在保存原有代码逻辑的基础上扩展功能,但是原有函数中的元信息会丢失,比如__name__, __doc__,参数列表。针对这种情况
可以使用functools.wraps,wraps也是一个装饰器,但是会将原函数的元信息拷贝到装饰器函数中。

具体使用方法:

from functools import wraps

def use_logging(level):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):

            if level == "warn":
                logging.warn("%s is running"% func.__name__)
            result = func(*args, **kwargs)
            print(result) 
            return result
        return wrapper
    return decorator

@use_logging("warn")
def test_decorator():
    """" Test Decorator DocString""""
    time.sleep(2)
    print("Test Decorator")
    return "Success"

print(test_decorator.__name__)
print(test_decorator.__doc__)

注解:

关于装饰器的执行顺序

在日常业务中经常会使用多个装饰器,比如权限验证,登录验证,日志记录,性能检测等等使用场景。所以在使用多个装饰器
时,就会涉及到装饰器执行顺序的问题。先说结论,关于装饰器执行顺序,可以分为两个阶段:(被装饰函数)定义阶段、(被装饰函数)执行阶段。

多装饰器示例:

def decorator_a(func):
    print("Get in Decorator_a")

    def inner_a(*args, **kwargs):
        print("Get in Inner_a")
        result = func(*args, **kwargs)
        return result
    return inner_a

def decorator_b(func):
    print("Get in Decorator_b")

    def inner_b(*args, **kwargs):
        print("Get in Inner_b")
        result = func(*args, **kwargs)
        return result
    return inner_b

@decorator_b    
@decorator_a
def test_decorator():
    """test decorator DocString"""
    print("Test Decorator")
    return "Success"

运行结果:

Get in Decorator_a
Get in Decorator_b
Get in Inner_b
Get in Inner_a
Test Decorator

代码注解:

参考链接

https://www.zhihu.com/question/26930016
https://segmentfault.com/a/1190000007837364
https://blog.csdn.net/u013411246/article/details/80571462

标签:粗浅,return,函数,Python,decorator,聊聊,test,装饰,def
来源: https://www.cnblogs.com/linshukai/p/14724833.html