装饰器

目录

 

1.复习函数

2.装饰器

3.装饰器用法

5.装饰器意义


1.复习函数

# (1).将函数赋予变量

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



send_message = func
send_message('hello world')

# (2)把函数当做参数传入到另一个函数中
def get_message(message):
    return 'Got a message:'+message

def root_call(func,message):
    print(func(message))

# (3)函数的嵌套
def func(message):
    def get_message(message):
        print('Got a message:{}'.format(message))
    return get_message(message)

# (4)函数的返回值也可以是函数对象(闭包)
def func(message):
    def get_message(message):
        print('Got a message:{}'.format(message))
    return get_message

2.装饰器

# (1)简单装饰器
# 这里的函数 my_decorator() 就是一个装饰器,它把真正需要执行的函数 greet() 包裹在其中,并且改变了它的行为,但是原函数 greet() 不变。
# 其实就是不改变 greet 与 greet 调用的情况下,将greet 函数变成了 wrapper 函数
def my_decorator(func):
    def wrapper():
        print('wrapper of deroctor')
        func()
    return wrapper

def greet():
    print('hello world')

greet = my_decorator(greet)
greet()


# @ 语法糖 如果其他程序也需要用这个装饰就在开头加上就行,提高函数的重复利用性与可读性

def my_decorator(func):
    def wrapper():
        print('wrapper of deroctor')
        func()
    return wrapper

@my_decorator
def greet():
    print('hello world')

# (2)带有参数的装饰器
# 在对应的装饰器函数 wrapper() 上,加上相应的参数
def my_decorater(func):
    def wrapper(message):
        print('wrapper of deroctor')
        func(message)
    return wrapper

@my_decorater
def greet(message):
    print(message)

greet('hello world')



# 通常情况下,我们会把*args和**kwargs,作为装饰器内部函数 wrapper() 的参数。*args和**kwargs,表示接受任意数量和类型的参数

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



# (3)带有自定义参数的装饰器
def repeat(num):
    def my_decorator(func):
        def wrapper(*args,**kwargs):
            for i in range(num):
                print(1)
                func(*args,**kwargs)
        return wrapper
    return my_decorator

@repeat(4)
def greet(v):
    print(v)


greet(4)

def greet(v):
    print(v)

greet = repeat(4)(greet)
greet(4)


# (4) 原函数还是原函数吗?
# 你会发现,greet() 函数被装饰以后,它的元信息变了。元信息告诉我们“它不再是以前的那个 greet() 函数,而是被 wrapper() 函数取代了”。
print(greet.__name__)
## 输出 'wrapper'
help(greet)
# 输出 Help on function wrapper in module __main__: wrapper(*args, **kwargs)
# 加 @functools.wraps(func)
import functools
def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args,**kwargs):
        print(1)
        func(*args,**kwargs)
    return wrapper

@my_decorator
def greet(message):
    print(message)

greet(2)

print(greet.__name__)
help(greet)

# (5)类装饰器
# 类也可以作为装饰器。类装饰器主要依赖于函数__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()
example()

# (6)装饰器的嵌套

@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')

3.装饰器用法

# 1.身份认证
#
# 这段代码中,我们定义了装饰器 authenticate;而函数 post_comment(),则表示发表用户对某篇文章的评论。每次调用这个函数前,
# 都会先检查用户是否处于登录状态,如果是登录状态,则允许这项操作;如果没有登录,则不允许
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.日志记录
# 在实际工作中,如果你怀疑某些函数的耗时过长,导致整个系统的 latency(延迟)增加,所以想在线上测试某些函数的执行时间,那么,装饰器就是一种很常用的手段。
import time
def execution_time(func):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        end_time = time.time()
        print('运行时间: {}'.format(str(end_time-start_time)))
    return wrapper

@execution_time
def greet(num):
    a = 0
    for i in range(num):
        a+=i
    print(a)

greet(1000)

# 3.输入合理性检查
# 其实在工作中,很多情况下都会出现输入不合理的现象。因为我们调用的训练模型往往很复杂,输入的文件有成千上万行,很多时候确实也很难发现。
# 试想一下,如果没有输入的合理性检查,很容易出现“模型训练了好几个小时后,系统却报错说输入的一个参数不对,成果付之一炬”的现象。这样的“*”,大大减缓了开发效率,也对机器资源造成了巨大浪费。
import functools

def validation_check(input):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        ...  # 检查输入是否合法

@validation_check
def neural_network_training(param1, param2, ...):
    ...

4.缓存
LRU cache,在 Python 中的表示形式是@lru_cache。@lru_cache会缓存进程中的函数参数和结果,当缓存满了以后,会删除 least recenly used 的数据。
@lru_cache
def check(param1, param2, ...) # 检查用户设备类型,版本号等等 ...

5.装饰器意义

这节课,我们一起学习了装饰器的概念及用法。所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。 
工作当中,如果是二次开发,在原来的需求基础之上做优化,原逻辑不需要修改的情况下,只需增加新的业务场景的时候,感觉用装饰器挺好的。不动原来的逻辑,增加程序的健壮性。
上一篇:最新版gradle安装使用简介


下一篇:mybatis-plus学习