python装饰器

一、装饰器如何使用

装饰器是用来“打扮函数”的,在程序开发中常常使用到装饰器,它使得开发效率更高,方便对代码进行扩展。一般我们写代码时遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。
封闭: 已经实现的功能代码块不允许修改
开放:对扩展功能进行开发

"""现在需要对下面三个模块进行功能扩展,在原来的基础上加入验证功能"""
def test1():
	print(‘--test1--’)

def test2():
	print('--test2--')

def test3():
	print('--test3--')

如果没有装饰器,那么传统的做法是先定义一个验证模块,然后每个模块进行调用即可。下面看代码

def verify():
	print("正在验证......")
	if "条件":
		print("验证成功!")
	else:
		print("验证失败,请确认!")
	
def test1():
	verify()
	print(‘--test1--’)

def test2():
    verify()
	print('--test2--')

def test3():
    verify()
	print('--test3--')

貌似利用上面的方法也可以实现。但是我们发现对原来的模块进行了修改,违反了“开放封闭原则”。接下来采用一种方法来避免这种情况。就是利用闭包的手段来避免对原来模块进行修改。

“”“验证模块设计”“”
def verify(func):
	def inner():
		print("正在验证......")
		if "条件":
			print("验证成功!")
			func() # 执行调用的函数
		else:
			print("验证失败,请确认!")
	return inner     # 返回函数inner()的引用

def test1():
	print(‘--test1--’)

def test2():
	print('--test2--')

def test3():
	print('--test3--')

# 下面分别为函数test1()、test2()、test3()添加验证功能
inner_fun = verify(test1)  # 这里的test1参数是将函数test1的引用给了参数func。
inner_fun()   # 执行函数,上面参数传入那个函数,调用内部函数时就执行相应的函数模块。

# test2()中加入验证功能
inner_fun = verify(test2)  # 这里的test2参数是将函数test2的引用给了参数func。
inner_fun()   # 执行函数,上面参数传入那个函数,调用内部函数时就执行相应的函数模块

#test3()中加入验证功能
inner_fun = verify(test2)  # 这里的test2参数是将函数test2的引用给了参数func。
inner_fun()   # 执行函数,上面参数传入那个函数,调用内部函数时就执行相应的函数模块

利用闭包的方法似乎解决了上面对原来函数进行修改的问题。这样满足了开放封闭原则,但是似乎函数写的不够优美。下面利用装饰器来简化上述代码。

“”“验证模块设计”“”
def verify(func):
	def inner():
		print("正在验证......")
		if "条件":
			print("验证成功!")
			func() # 执行调用的函数
		else:
			print("验证失败,请确认!")
	return inner     # 返回函数inner()的引用

@verify                 # 等价于:inner_fun = verify(test1)
def test1():
	print(‘--test1--’)

@verify                # 等价于:inner_fun = verify(test2)
def test2():
	print('--test2--')

@verify               # 等价于:inner_fun = verify(test3)
def test3():
	print('--test3--')
"""可以看到将上面代码分别加入了@verify,这一句代码表示的意思等价于: inner_fun = verify(test1)"""

那么装饰器函数在什么时候进行装饰? 只要上面一段代码写了@verify后,执行上面的代码后,就进行了装饰。我们会发现上面函数只是定义好了,但是还没有调用函数怎么会执行呢?这就时装饰器的一个特点,只要定义了装饰器 ,那么在调用函数之前就进行了装饰,而不是等到调用函数时才进行装饰,这一点要清楚。

下面对函数进行调用:

# 调用test1
test1()

# 调用test2
test2()

# 调用test3
test3()
“”“其实我们发现比之前不用装饰器时代码更加简洁。可以回过头对比下之前没用装饰器时的代码。””“

二、两个装饰器函数

# 定义装饰函数
def makeBold(fn):
	def wrapped():
		return "<b>" + fn() + "</b>"
	return wrapped

# 定义装饰函数
def makeItalic(fn):
	def wrapped():
		return "<i>" + fn() + "</i>"
	return wrapped
# @ makeBold 等价于 fn = makeBold(test)
@makeBold     # 后装饰,先调用(执行)

# @ makeItalic 等价于 fn = makeItalic(test)
@makeItalic   # 先装饰,后调用 (靠近函数的先装饰,后调用)
def test():
	return "--两个装饰函数共同装饰--" 	

# 调用函数test
test()
输出结果:
<b><i> --两个装饰函数共同装饰--<i><b>

三、带有参数的装饰器

装饰器带有参数,在原有的装饰器的基础上,设置外部变量。

# 下面的例子是装饰器带有参数的情况
from time import ctime,sleep
def timefun_arg(parse):
	def timefun(func):
		def wrappedfun():
			print("%s called %s %s"% (func.__name__,ctime(),parse))
		    return func
	    return wrappedfun
	return timefun

@timefun_arg("test") 
“”“先调用timefun_arg()这个函数,函数的返回值作为装饰,即timefun, 这里相当于@ timefun,与上面讲过的装饰器是一样的,只不过多了传参数的这一步。”“”
def test1():
	print("---test1---")

@timefun_arg("python")
def test2():
	print("---test2---")

test1()   # 输出结果:test1 called Mon Feb 10 08:48:00 2020 test
sleep(2)
test2()   # 输出结果:test2 called Mon Feb 10 08:48:02 2020 python

那么上面带参数的装饰器有什么作用呢?如果我们只有一个装饰器,让它根据不同的参数进行特定的判断,或者其他操作。将上面的列子加上判断后看看效果。

from time import ctime,sleep
def timefun_arg(parse):
	def timefun(func):
		def wrappedfun():
		    if parse == "Python":
				print("This is %s"%parse)
			else: 
				print("Others")
		    return func
	    return wrappedfun
	return timefun

@timefun_arg("test") 
“”“先调用timefun_arg()这个函数,函数的返回值作为装饰,即timefun, 这里相当于@ timefun,与上面讲过的装饰器是一样的,只不过多了传参数的这一步。”“”
def test1():
	print("---test1---")

@timefun_arg("Python")
def test2():
	print("---test2---")

# 调用函数
test1()   # 输出结果:Others
sleep(2)  
test2()   # 输出结果:This is Python
“”“可以通俗的说,带参数的迭代器可以根据不同参数进行特定的作用!”“”
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值