• Python进阶: Decorator 装饰器你太美


    函数 -> 装饰器

      函数的4个核心概念

      1.函数可以赋与变量

    def func(message):
        print('Got a message: {}'.format(message))
    
    send_message = func
    send_message('hello world')
    #输出
    #Got a message: hello world

      2.函数可以当作函数的参数

    def get_message(message):
        return 'Got a message: ' + message
    
    def root_call(func, message):
        print(func(message))
    
    root_call(get_message, 'hello world')
    输出
    #Got a message: hello world

      3.函数里嵌套函数

    def func(message):
        def get_message(message):
            print('Got a message: {}'.format(message))
        return get_message(message)
    
    func('hello world')
    输出
    #Got a message: hello world

      4.函数作为函数返回值(闭包)

    def func_closure():
        def get_message(message):
            print('Got a message: {}'.format(message))
        return get_message
    
    send_message = func_closure()
    send_message('hello world')
    #输出
    #Got a message: hello world
     

    简单装饰器

      例

    def my_decorator(func):
        def wrapper():
            print('wrapper of decorator')
            func()
        return wrapper
    
    def greet():
        print('hello world')
    
    greet = my_decorator(greet)
    greet()

      使用语法糖 @

    def my_decorator(func):
        def wrapper():
            print('wrapper of decorator')
            func()
        return wrapper
    
    @my_decorator
    def greet():
        print('hello world')
    
    greet()
    # 输出
    # wrapper of decorator
    # hello world

    带有参数的装饰器

      直接在 wrapper函数中加上参数
    def my_decorator(func):
        def wrapper(message):
            print('wrapper of decorator')
            func(message)
        return wrapper
    
    
    @my_decorator #相当于 greet == wrapper(message)
    def greet(message):
        print(message)
    
    greet('hello world')
    # 输出
    #wrapper of decorator
    #hello world

      这个装饰器只能用在有一个参数的函数,如果想对任意参数的函数通用,可以这么写

    def my_decorator(func):
        def wrapper(*args, **kwargs):
            print('wrapper of decorator')
            func(*args, **kwargs)
        return wrapper

    带自定义参数的装饰器

      利用装饰器自定义参数这特性,实现重复执行装饰器内部函数
    def repeat(num):
        def my_decorator(func):
            def wrapper(*args, **kwargs):
                for i in range(num):
                    print('wrapper of decorator')
                    func(*args, **kwargs)
            return wrapper
        return my_decorator
    
    
    @repeat(4)
    def greet(message):
        print(message)
    
    greet('hello world')
    
    # 输出:
    # wrapper of decorator
    # hello world
    # wrapper of decorator
    # hello world
    # wrapper of decorator
    # hello world
    # wrapper of decorator
    # hello world

    原函数还是原函数?

    greet.__name__
    #输出
    'wrapper'
    
    help(greet)
    # 输出
    Help on function wrapper in module __main__:
    
    wrapper(*args, **kwargs)

      可以看出,原函数的原信息会被wrapper取代

      如果不想其改变,那么可用内置装饰器@functools.wraps将原函数的元信息拷贝过去。
    import functools
    
    def my_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('wrapper of decorator')
            func(*args, **kwargs)
        return wrapper
    
    @my_decorator
    def greet(message):
        print(message)
    
    greet.__name__
    
    # 输出
    #'greet'

     类装饰器

      类装饰器主要依赖于 __call__()函数,每当调用类实例时,__call__()函数会被执行一次
    class Count:
        def __init__(self, func):
            self.func = func
            self.num_calls = 0
    
        def __call__(self, *args, **kwargs):
            self.num_calls += 1
            print('num of calls is: {}'.format(self.num_calls))
            return self.func(*args, **kwargs)
    
    @Count
    def example():
        print("hello world")
    
    example()
    
    # 输出
    # num of calls is: 1
    # hello world
    
    example()
    
    # 输出
    # num of calls is: 2
    # hello world

    装饰器的嵌套

    @decorator1
    @decorator2
    @decorator3
    def func():
        ...
    #相当于 decorator1(decorator2(decorator3(func)))
    import functools
    
    def my_decorator1(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('execute decorator1')
            func(*args, **kwargs)
        return wrapper
    
    
    def my_decorator2(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('execute decorator2')
            func(*args, **kwargs)
        return wrapper
    
    
    @my_decorator1
    @my_decorator2
    def greet(message):
        print(message)
    
    
    greet('hello world')
    
    # 输出
    # execute decorator1
    # execute decorator2
    # hello world

    装饰器的实例用法

      1)身份验证,不登录不允许操作

    import functools
    
    def authenticate(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            request = args[0]
            if check_user_logged_in(request): # 如果用户处于登录状态
                return func(*args, **kwargs) # 执行函数 post_comment()
            else:
                raise Exception('Authentication failed')
        return wrapper
    
    @authenticate
    def post_comment(request, ...)
        ...

      2)日志记录 可测试函数的执行时间

    import time
    import functools
    
    def log_execution_time(func):
        def wrapper(*args, **kwargs):
            start = time.perf_counter()
            res = func(*args, **kwargs)
            end = time.perf_counter()
            print('{} took {} ms'.format(func.__name__, (end - start) * 1000))
            return res
        return wrapper
    
    @log_execution_time
    def calculate_similarity(items):
        ...

      3) 合法性检测

    import functools
    
    def validation_check(input):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            ... # 检查输入是否合法
    
    @validation_check
    def neural_network_training(param1, param2, ...):
        ...
    
    LRU cache. @lru_cache缓存装饰器
    @lru_cache
    def check(param1, param2, ...) # 检查用户设备类型,版本号等等
        ...

      4) try...excaption

    class ServerDebugHelper:
        @classmethod
        def debug(cls):
            def decorator(func):
                @wraps(func)
                def wrapper(*args, **kwargs):
                    try:
                        return func(*args, **kwargs)
                    except:
                        import traceback
                        print(traceback.format_exc())
                return wrapper
            return decorator

      

    参考

      极客时间《Python核心技术与实战》专栏

  • 相关阅读:
    jquery选择器
    js中的闭包技术
    idea创建servlet不能创建:
    JSP页面不解析EL表达式的原因
    大对象数据LoB的应用
    缓冲流、转换流、序列化流相关流知识点
    jdk5.0新特性(注解)
    EKT相关知识(Class类对象的方法补充)
    java中调用存储过程或函数
    Java 缓冲流
  • 原文地址:https://www.cnblogs.com/xiaoguanqiu/p/11046744.html
Copyright © 2020-2023  润新知