『Python 装饰器』小结


什么是装饰器(decorator)?

顾名思义,它是一个用来装饰函数的东西。具体点,装饰器是一个用来增加函数功能 ("装饰"一词就这么来的) 的东西。

装饰器由两部分组成:

  1. 装饰函数,例如函数名叫 dec。
  2. 一行 “@dec” 加在被装饰的函数上。

如果通过装饰器来增加函数的功能,有以下优点:

  1. 不改变被增强函数的内部代码。
  2. 不改变函数的调用方式。

如何增加函数的功能

假如有以下函数。

import time
def test():
	print('running test function...')
	time.sleep(0.5)

test()

这个 test 函数的内部代码如上所示,调用方式为 test()。
现在,你想增加这个函数的功能:除了输出一句"running test function…"之外,还输出从运行到结束函数占用的时间。
要求:不可以改变 test 函数的内部代码,但可以改变函数的调用方式

import time

def test():
	print('test function')
	time.sleep(0.5)

def timer(func):
	start = time.time()
	func()
	end = time.time()
	print('running time:', end - start)

timer(test)

上面的代码中,timer 函数接受的参数是一个函数名。func 参数接收到之后,就可以通过 func() 调用传来的 test 函数。

好了,现在又有了新的要求:不可以改变 test 函数的内部代码,也不可以改变函数的调用方式
于是就有了下面的代码:

import time

def decorator(func):
	def wrapper():
		start = time.time()
		func()
		end = time.time()
		print('running time:', end - start)
	return wrapper

def test():
	print('test function')
	time.sleep(0.5)

test = decorator(test)
test()

decorator 函数就是一个装饰函数,它接收一个函数对象,返回一个函数对象,中间过程就是对接收的函数对象封装的过程。
我是这么理解的:传进来的 func 函数对象是一小盘沙子,但是你想要一大盘沙子,内部嵌套定义的 wrapper 函数是一个大盘子,把那一小盘沙子(func 函数)放进大盘子里,然后再加上些必要的沙子(监测时间的代码),这一大盘沙子(wrapper函数)就是你想要的了。

请你仔细阅读上面的代码,这段代码是一个最简单的装饰器的本质。里面包含了嵌套函数、函数名传参的相关知识,如果无法理解,不建议继续往下读。


真正的装饰器

删除上面倒数第二行的代码 test = decorator(test),新增加一行 @decorator,其他代码一点未变。

import time

def decorator(func):
	def wrapper():
		start = time.time()
		func()
		end = time.time()
		print('running time:', end - start)
	return wrapper

@decorator  # 增加这一行
def test():
	print('test function')
	time.sleep(0.5)

# test = decorator(test)  删除这一行
test()

这便是装饰器 — 装饰函数 decorator + “@decorator”。
其实,@decorator 这句话完全等价于 test = decorator(test)
运行代码,得到结果

test function
running time: 0.5002768039703369

装饰器的实质

其实,接着上部分关于沙子的比喻,装饰器实质上就是把小盘沙子封装了一下,用大些的盘子装起来。也就是装饰之后的test函数其实是 wrapper 函数:

import time

def decorator(func):
	def wrapper():
		start = time.time()
		func()
		end = time.time()
		print('running time:', end - start)
	print(id(wrapper))
	return wrapper

@decorator  # 增加这一行
def test():
	print('test function')
	time.sleep(0.5)

# test = decorator(test)  删除这一行
print(id(test))
2829141796248
2829141796248

结果在不一样的电脑上是不一样的,但是能确定的是输出的两个函数入口地址是相同的。
这也就验证了上面的一句话:

@decorator 这句话完全等价于 test = decorator(test)


带参数的装饰器

废话不多说,上代码,修改部分已在注释部分说明。

import time

def decorator(func):
	def wrapper(param):  # wrapper 函数加上参数
		start = time.time()
		func(param)  # 调用时加上参数
		end = time.time()
		print('running time:', end - start)
	return wrapper

@decorator
def test(param):  # 若被修饰函数带参数,则在 wrapper 函数做相应修改
	print('test function')
	time.sleep(0.5)

test()

看了几篇博客后对于装饰器的浅薄理解,如果有不对处请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值