浅谈python中@装饰器
文章目录
- 浅谈python中@装饰器
- 关于装饰器(decorator)
- 小总结
- 关于@(语法糖)
- 进阶
- 装饰器顺序
- 装饰器 & 参数
- End
提到@的使用首先要先讲一下装饰器的概念
关于装饰器(decorator)
先来看看官方文档上面是怎么写的:
A decorator is the name used for a software design pattern. Decorators
dynamically alter the functionality of a function, method, or class
without having to directly use subclasses or change the source code of
the function being decorated.
“装饰器是用于软件设计模式的名称。 装饰器可以动态更改功能,方法或类的功能,而不必直接使用子类或更改要修饰的功能的源代码。”(源自谷歌翻译)
而在python中装饰器是对python语法的特定更改,能更方便的修改函数和方法。通俗的说,装饰器相当于在不修改原有函数的基础上在其上增加别的功能。比如说我想每次使用函数的时候都打印一条日志作为标记,但是我又不想直接修改函数,这时装饰器就有用啦。装饰顾名思义是锦上添花的意思,在这个例子里“花”就是日志喽,大概是这样。
def triple_sum(a,b,c):
print( "the sum is ",(a+b+c))
#log修饰器
def log_dec(func):
def inner(a,b,c):
print("logloglog")
return func(a,b,c)
return inner
new_fun=log_dec(triple_sum)
new_fun(1,2,3)
输出为
这里还有个隐含的前置知识点,在python里,函数可以作为变量进行传递。
def triple_sum(a, b, c):
print( "the sum is ",(a+b+c))
new_func = triple_sum
new_func(123, 234, 345)
print(new_func.__name__)
除了函数之外,类也可以作为装饰器进行包装
class Cube(object):
def __init__(self, args):
self.args = args
def __call__(self, x, y):
res = self.args(x, y)
return res * res * res
# 这里Cube作为一个三次方的包装器,包装了一个普通的乘法函数
# 这里的乘法函数我用一个lambda表达式来略缩了
mul_nums = Cube(lambda x, y: x * y)
# 不使用lambda函数的话就是
#def mul_nums(x, y):
# return x * y
#mul_nums = Cube(mul_nums)
print(mul_nums)
print(mul_nums(4, 3))
小总结
所以装饰器是什么,其实只是给当前的模块增加的新功能。装饰器可以是类,也可以是函数。它不会改变原来的函数本身,符合设计方法的开闭原则。
关于@(语法糖)
@ 实际上是python的语法糖,使用@对上面的两个例子进行改造
示例1:
def log_dec(func):
print("logloglog")
func(1,2,3)
@log_dec
def triple_sum(a,b,c):
print( "the sum is ",(a+b+c))
结果输出为:
公式化一下@这个语法糖就是
@装饰器名 替代掉了 装饰器名(被装饰的函数)
即 triple_sum = log_dec(triple_sum)
示例2
@Cube
def mul_nums(x, y):
return x * y
同理,@Cube替掉了mul_nums = Cube(mul_nums)
进阶
装饰器顺序
需要注意的是,想在已有函数上加的功能,需要在@之前声明(代码块的先后顺序)。同时,一个函数可以同时加几个装饰器。
从最下面的一个@函数开始运行,其下的函数作为他的输入。用print会看的更清楚一点
def log1(func):
print("log1log1log1")
def log2(func):
print("log2log2log2")
func(1, 2, 3)
@log1
@log2
def triple_sum(a, b, c):
print("the sum is ", (a + b + c))
输出为:
实际的运行相当于
triple_sum = log2(triple_sum)
triple_sum = log1(triple_sum)
装饰器 & 参数
1. 传参
可能有些盲生看到这里已经发现了华点,咋给triple_sum传参啊!(上面例子里面的值全都是写死的)这里我们就要对装饰器进行改造了。
在改造之前,需要知道一个前置知识,python中可以进行函数的嵌套,如
def func1():
print("I'm in func1")
def func2(msg):
print("I'm in func2")
print("I'm saying ",msg)
func2("hello")
func1()
清楚了函数嵌套,再来看怎么改造装饰器参数
def log1(func):
def wrapper(*args):
print("logloglog")
func(*args)
return wrapper
@log1
def triple_sum(a, b, c):
print("the sum is ", (a + b + c))
triple_sum(100,200,300)
使用函数嵌套就完成了装饰器的传参
2. 带参装饰器
此外,装饰器本身也可以携带参数。依然使用函数嵌套,再来一层。
def log_with_args(arg1,arg2):
def log1(func):
def wrapper(*args):
print("logloglog")
func(*args)
print("arg1 is ",arg1,", args2 is ", arg2)
return wrapper
return log1
@log_with_args("hello","world")
def triple_sum(a, b, c):
print("the sum is ", (a + b + c))
triple_sum(111,222,333)
End
以上即为装饰器的全部内容,欢迎评论区沟通指正。
参考
- 菜鸟教程 Python 函数装饰器
- 一大佬的文章,讲得很清楚