关于Python 装饰器的一些理解——为什么要用装饰器(1)

0 引言

  • Python最大的一个特点是简单,很多代码都可以写的很优雅,本人在Python学习过程中也尽可能将代码简化,也会在网上看看一些文章。当我看到装饰器的时候,发现简单一行可以实现很麻烦的一个功能,所以决定去了解一下。我在b站和微信公众号上都看了很多博主的介绍,有些博主讲的很详细,甚至有些大神从代码原理开始讲,我也是看了不同版本的解释才大概懂了。这里写一篇文章聊聊我自己对装饰器的理解,如果有什么不对的地方大神可以指出来。
    接下来我主要从为什么要用装饰器来讲,过程可能会比较啰嗦,但还是比较容易理解。

1 为什么要用装饰器

  • 我们平时在写代码时,会把常用的一些功能写在一个函数里,方便后面多次重复使用。比如下面我们要实现相加的功能:
def plus(a,b):
	return a+b
sum=plus(a,b)
  • 但是我们的 a 和 b 不是凭空来的,这里我们通过 input 函数来获取 a 和 b。
def plus(a,b):
	return a+b
	
a=input('please input a')
b=input('please input b')
sum=plus(a,b)
  • 我们可以把上述代码写在一个函数中,方便其他地方调用。
def plus(a,b):
	return a+b
def run():	
	a=input('please input a')
	b=input('please input b')
	ret=plus(a,b)
	return ret
sum_ab=run()
  • 此时如果我们还需要一个求两个数的乘积的函数,就需要再写一个类似的函数:
def multiply(a,b):
	return a*b
def run():	
	a=input('please input a')
	b=input('please input b')
	ret=multiply(a,b)
	return ret
sum_ab=run()
  • 这就产生了很多的重复代码,看起来也一点不优雅,而且通用性不强。我们仔细看会发现,run 函数内只是把 plus 函数变成了 multiply 函数,那如果可以把 plus 函数或 multiply 函数当参数传到 run 函数就可以了。这里需要强调一下,函数可以作为参数传递到函数中。
def multiply(a,b):
	return a*b
def run(fun):
    a=int(input('please input a'))
    b=int(input('please input b'))
    ret=fun(a,b)
    return ret
run(multiply)
  • 这样我们基本可以是实现对 a 和 b 的不同操作。但是这个方法的通用性不强,因为fun 函数可能还有其他需要传入的参数,而这个参数不在 run 函数内,比如我们在 multiply 函数内将乘积结果打印出来,那就需要用到 *args 和 **kwargs ,他俩分别代表任意参数和任意关键字参数。对上面的代码进行改进后如下:
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
def run(fun,*args,**kwargs):					# 飞雷神标记
    a=int(input('please input a'))
    b=int(input('please input b'))
    ret=fun(a,b,*args,**kwargs)
    return ret
run(multiply,show=True)
# please input a1
# please input b2
# 2
  • 此时,我们基本能够实现了我们想要的功能,但是每次将函数当作参数传入函数的写法实在不优雅。所以我们决定将 run 函数换一种写法,首先我们将 fun 函数和他的参数分开,将fun参数提出来:
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
fun=multiply
def run(*args,**kwargs):
    a=int(input('please input a'))
    b=int(input('please input b'))
    ret=fun(a,b,*args,**kwargs)
    return ret
run(show=True)
  • 因为 fun 变量是一个函数,并且在 run 函数外面,因此 run 函数内部可以调用到 fun 变量。此时,我们再调用 run 函数时就不用输入函数名了。但是这个代码看起来又很乱,代码越优化越乱了,怎么办呢,继续优化。所以我们可以将 fun 变量和 run 函数一起写在一个函数中:
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
def dec():
	fun=multiply
	def run(*args,**kwargs):
	    a=int(input('please input a'))
	    b=int(input('please input b'))
	    ret=fun(a,b,*args,**kwargs)
	    return ret
dec()
  • 这样代码看着就整齐一些了,但是当我们运行这个 dec 函数时会发现没有任何输出,这是因为我们在 dec 函数中定义了 run 函数,但是没有调用函数,所以只需要在 dec 函数中调用一下 run 函数就可以了:
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
def dec():
	fun=multiply
	def run(*args,**kwargs):
	    a=int(input('please input a'))
	    b=int(input('please input b'))
	    ret=fun(a,b,*args,**kwargs)
	    return ret
	run()
dec()
  • 此时便可以正常运行了,暂时先不管 show 参数。为了方便修改 fun 我们直接把 fun 设为 dec 函数的参数,这样方便修改需要运行的函数,代码也会简单一些,run 函数的返回值就是我们前面飞雷神标记的函数返回值,因此可以直接将 run 函数结果作为 dec函数的返回值,修改后如下:
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
def dec(fun):
	def run(*args,**kwargs):
	    a=int(input('please input a'))
	    b=int(input('please input b'))
	    ret=fun(a,b,*args,**kwargs)
	    return ret
	return run()
dec(multiply)
  • 到这里,我们发现 dec 函数返回的 run 函数传参数很不方便,如果在 dec 函数中传*args 和**kwargs 那就和前面飞雷神标记的 run 函数没有区别了,所以我们可以在 dec 函数中不直接返回 run 函数的返回值,而是返回 run 函数本身,然后在外部调用 run(*args,**kwargs) 得到 run 函数的返回值。
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
def dec(fun):
	def run(*args,**kwargs):
	    a=int(input('please input a'))
	    b=int(input('please input b'))
	    ret=fun(a,b,*args,**kwargs)
	    return ret
	return run
mul_run=dec(multiply)			# dec_fun1
ret=mul_run(show=True)			# dec_fun2
  • 如上,由于在定义 run 函数时 fun 函数传入的是 multiply 函数,所以 mul_run 就是 fun 函数为 multiply 的 run 函数了,此时只要运行 mul_run 函数并传入参数即可得到返回值。此时,dec 函数就是装饰函数,我们在 multiply 函数上方添加 @dec 后,后面直接执行 multiply 函数,等价于执行上面 dec_fun1 和 dec_fun2 。
def dec(fun):
	def run(*args,**kwargs):
		a=int(input('please input a'))
		b=int(input('please input b'))
		ret=fun(a,b,*args,**kwargs)
		return ret
	return run
@ dec
def multiply(a,b,show=False):
	if show:
		print (a*b)
	return a*b
ret=multiply(show=True)
  • 上面我们看了为什么要用装饰器,从这个过程中我们可以看到装饰器真的很优雅。接下来我将说一说装饰器适用于什么样的情况。
  • 鼠标给媳妇用了,没有鼠标码字又要调整格式很慢,这篇文章码了好久,所以装饰器的使用场景放到下一篇。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值