Python基础 —— 装饰器

1、装饰器的特点

我们希望在不修改原函数的情况下,来对函数进行扩展。

2、传统方法:对 add函数 增加日志打印

def add(a , b):
    '''
        求任意两个数的和
    '''
    r = a + b
    return r

def print_log(func):            # print_log 就是 装饰器函数 
    
     # 创建一个新函数
    def new_function(*args , **kwargs):
        print('开始执行~~~~')    
        result = func(*args , **kwargs)
        print('执行结束~~~~')       
        return result
            
    return new_function

# 此处传 add 引用, 而不是调用 add() 。如果传 add(),是将add函数执行完毕后的结果传进去
r=print_log(add)

print('求和:',r(10 , 30))

运行结果:

开始执行~~~~
执行结束~~~~
求和: 40

3、使用 装饰器 对上面代码优化

def print_log(func):            # print_log 就是 装饰器函数 
    
     # 创建一个新函数
    def new_function(*args , **kwargs):
        print('开始执行~~~~')    
        result = func(*args , **kwargs)
        print('执行结束~~~~')       
        return result    
    return new_function


@print_log         # 装饰器print_log函数 对 add函数 进行扩展
def add(a , b):
    '''
        求任意两个数的和
    '''
    r = a + b
    return r
 
r=add(10 , 30)
print('求和:',r)

运行结果与上面是一致的:

开始执行~~~
执行结束~~~
求和: 40

print_log() 这种函数我们就称它为 装饰器

通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展。
在定义函数时,可以通过 @ 装饰器,来使用指定的装饰器,来装饰当前的函数,
可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰。

说明:

*args 表示接收所有的 位置参数;
**kwargs 表示接收所有的 键值参数 。

函数的形参有两数:位置参数 和 键值参数

4、使用多个装饰器


def print_log(func):            # print_log 就是 装饰器函数 
    
     # 创建一个新函数
    def new_function(*args , **kwargs):
        print('开始执行~~~~')    
        result = func(*args , **kwargs)
        print('执行结束~~~~')       
        return result    
    return new_function

def fn3(func):
    
    # 创建一个新函数
    def new_function(*args , **kwargs):
        print('fn3装饰~开始执行~~~~')       
        result = func(*args , **kwargs)
        print('fn3装饰~执行结束~~~~')      
        return result
   
    return new_function

@fn3
@print_log
def add(a , b):          # add上有两个装饰器去其进行扩展
    '''
        求任意两个数的和
    '''
    r = a + b
    return r
 
r=add(10 , 30)
print('求和:',r)

运行结果:

fn3装饰~开始执行~~~~
开始执行~~~~
执行结束~~~~
fn3装饰~执行结束~~~~
求和: 40

5、带有参数的装饰器

5.1、传统方式

调用不同函数,要有不同的权限验证。
比如 调用test1() 函数时,就要验证 是否有test1的权限;调用test2() 函数时,就要验证 是否有 test2的权限。

# 定义装饰器函数
def set_func(func):
    def call_func(*args,**kwargs):
        level = args[0]
        if level == 1:
            print("------- 权限级别1 ,验证------------")
        elif level == 2:
            print("-------- 权限级别2,验证------------")
        return func()
    return call_func


## 定义 test1 函数
@set_func
def test1():
    print("-------test1----------")
    return "ok"
    
# 定义 test2 函数
@set_func
def test2():
    print("-------test2----------")
    return "ok"

## 调用函数时,要传入权限级别的值
test1(1)
test2(2)

运行结果:

------- 权限级别1 ,验证------------
-------test1----------
-------- 权限级别2,验证------------
-------test2----------

说明:

对 test1()、test2() 的权限级别 是让 调用者 来设置, 调用者 可以随意设置 权限级别,那就就没有任何的安全可言。所以上面的方式是不可取的。

正确的做是 在函数 定义时 加上相应的权限级别,而 调用者只是调用。

5.2、使用带有参数的装饰器

@set_func 装饰器 外层 再增加一层装饰器 set_level

# 定义装饰器函数
def set_level(level_num):
    def set_func(func):
        def call_func(*args,**kwargs):            
            if level_num == 1:
                print("------- 权限级别1 ,验证------------")
            elif level_num == 2:
                print("-------- 权限级别2,验证------------")
            return func()
        return call_func
    return set_func


# 定义 test1 函数
@set_level(1)
def test1():
    print("-------test1----------")
    return "ok"

# 定义 test2 函数
@set_level(2)
def test2():
    print("-------test2----------")
    return "ok"

# 调用
test1()
test2()

运行结果跟上面一致:

------- 权限级别1 ,验证------------
-------test1----------
-------- 权限级别1,验证------------
-------test2----------

6、类装饰器

class Test(object):
    
    def __init__(self,func):            
       self.func=func
    
    def __call__(self):
        print("这里是装饰器添加的功能")
        return self.func()

@Test                # 相当于 get_str=Test(get_str) ,调用类中的__call__
def get_str():
    return "zhangsan"


# 调用
print(get_str())

运行结果:

这里是装饰器添加的功能
zhangsan

猜你喜欢

转载自blog.csdn.net/xiaojin21cen/article/details/107931451