Decorator装饰器学习(引用 秋官大大 https://www.cnblogs.com/xiaoguanqiu/p/11046744.html)

一、装饰器函数的4个核心概念

1.函数可以赋与变量

def func(message):
    print('Got a message: {}'.format(message))

send_message = func
send_message('hello world')
#输出
#Got a message: hello world
按 Ctrl+C 复制代码

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值