Python 装饰器解析

一、装饰器定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能

二、装饰器的作用:在不改变原函数的情况下,为原函数前后添加新的功能

三、装饰器的原则:

  1、不能修改被装饰的函数的源代码

  2、不能修改被装饰函数的调用方式

四、装饰器的组成:由作用域、高阶函数以及闭包组成

  闭包的概念:如果在一个内部函数里面,对外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包

 

五、装饰器模板:

需要注意的是带参数的装饰器执行顺序为先执行@符号后面的内容,即先将参数传进装饰器中

def wrapper(func):
    def inner(*args,**kwargs):
        '被装饰函数之前添加的内容'
        ret = func(*args,**kwargs)
        '被装饰函数之后添加的内容'
        return ret
    return inner
普通装饰器模板
def outer(形参)
    def wrapper(func):
        def inner(*args,**kwargs):
            '被装饰函数之前添加的内容'
            ret = func(*args,**kwargs)
            '被装饰函数之后添加的内容'
            return ret
        return inner
    return wrapper

@outer(True)
def  原函数()
带参数的装饰器模板

 

六、装饰器实例

实例一、

# 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
# 2.要求登录成功一次,后续的函数都无需再输入用户名和密码

"""
思路:
1、首先写两个其他需要被装饰的函数
2、然后写装饰器函数模板
3、补充优化装饰器函数的内容,即登录功能的验证
"""
代码:
FLAG = False    #设置状态,用来判断当前是否已经成功登陆

def login(func):
    def inner(*args, **kwargs):
        global FLAG
        if FLAG:
            ret = func(*args, **kwargs)
            return ret
        else:
            username = input('请输入用户名:')
            password = input('请输入密码:')
            if username == 'bangsheng' and password == '123456':
                FLAG = True    #成功登陆后改变状态值
                ret = func(*args, **kwargs)  # func是被装饰的函数
                return ret
            else:
                print('登录失败')

    return inner


@login
def shop_add():
    print('添加一件商品')

#多个装饰器装饰一个函数,执行顺序为先执行离def最近的那个装饰器,这里表示先执行@log这个装饰器
@login
def shop_del():
    print('删除一件商品')

shop_add()
shop_del()

 

实例二、

# 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
import time
def log(func):
    def inners(*args, **kwargs):
        with open('log', 'a', encoding='utf-8') as f:
            f.write(str(time.strftime('%Y-%m-%d %H:%M:%S')) + ' ' + (func.__name__ + '\n'))
            '''
            time.strftime为格式化输出时间,
            time.time()获取的时间格式为1970年到现在的秒数
            time.local.time()获取到的也是秒数
            '''
        ret = func(*args, **kwargs)
        return ret

    return inners

@log
def shop_add():
    print('添加一件商品')

@log
def shop_del():
    print('删除一件商品')


shop_add()
shop_del()

 

实例三、多个装饰器装饰同一个函数

#多个装饰器装饰一个函数,执行顺序为先执行离def最近的那个装饰器,这里表示先执行@log这个装饰器
 1 import time
 2 
 3 FLAG = False
 4 
 5 
 6 def login(func):
 7     def inner(*args, **kwargs):
 8         global FLAG
 9         if FLAG:
10             ret = func(*args, **kwargs)
11             return ret
12         else:
13             username = input('请输入用户名:')
14             password = input('请输入密码:')
15             if username == 'bangsheng' and password == '123456':
16                 FLAG = True
17                 ret = func(*args, **kwargs)  # func是被装饰的函数
18                 return ret
19             else:
20                 print('登录失败')
21 
22     return inner
23 
24 
25 # 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
26 def log(func):
27     def inners(*args, **kwargs):
28         with open('log', 'a', encoding='utf-8') as f:
29             f.write(str(time.strftime('%Y-%m-%d %H:%M:%S')) + ' ' + (func.__name__ + '\n'))
30             '''
31             time.strftime为格式化输出时间,
32             time.time()获取的时间格式为1970年到现在的秒数
33             time.local.time()获取到的也是秒数
34             '''
35         ret = func(*args, **kwargs)
36         return ret
37 
38     return inners
39 
40 
41 @login
42 @log
43 def shop_add():
44     print('添加一件商品')
45 
46 #多个装饰器装饰一个函数,执行顺序为先执行离def最近的那个装饰器,这里表示先执行@log这个装饰器
47 @login
48 @log
49 def shop_del():
50     print('删除一件商品')
51 
52 
53 shop_add()
54 shop_del()
多个装饰器装饰同一个函数

 

实例四、带参数的装饰器

'''
通过一个带参数的装饰器可以整体控制装饰器是否生效
只需要在全局变量中将FLAGE的状态变化为False就可以使装饰器失效
'''
 1 '''
 2 带参数的装饰器,可以通过一个参数来控制装饰器是否被启用
 3 '''
 4 
 5 FLAGE = True
 6 def timmer_outer(FLAGE):
 7     def timmer(func):
 8         def inner(*args,**kwargs):
 9             if FLAGE:
10                 start = time.time()
11                 ret = func(*args,**kwargs)
12                 end = time.time()
13                 print(start-end)
14                 return ret
15             else:
16                 ret = func(*args,**kwargs)
17                 return ret
18         return inner
19     return timmer
20 
21 '''
22 通过一个带参数的装饰器可以整体控制装饰器是否生效
23 只需要在全局变量中将FLAGE的状态变化为False就可以使装饰器失效
24 '''
25 @timmer_outer(FLAGE)
26 def nufront():
27     time.sleep(0.1)
28     print('新岸线公司')
29 
30 @timmer_outer(FLAGE)
31 def hst():
32     time.sleep(0.2)
33     print('HST')
带参数的装饰器

posted @ 2018-12-11 10:56  hubangsheng  阅读(235)  评论(0编辑  收藏  举报