python 进阶篇 函数装饰器和类装饰器
2024-08-31 21:54:00
函数装饰器
简单装饰器
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper def greet():
print('hello world') greet = my_decorator(greet)
greet() # 输出
# wrapper of decorator
# hello world
上述代码在 Python 中有更简单、更优雅的表示:
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper @my_decorator
def greet():
print('hello world') greet() # 输出
# wrapper of decorator
# hello world
带参数的装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper @my_decorator
def greet(message):
print(message) greet('hello world') # 输出
# wrapper of decorator
# hello world
自定义参数的装饰器
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator {}'.format(i))
func(*args, **kwargs)
return wrapper
return my_decorator @repeat(4)
def greet(message):
print(message) greet('hello world') # 输出:
# wrapper of decorator 0
# hello world
# wrapper of decorator 1
# hello world
# wrapper of decorator 2
# hello world
# wrapper of decorator 3
# hello world
原函数还是原函数吗?
试着打印出 greet() 函数的一些元信息:
greet.__name__
## 输出
'wrapper' help(greet)
# 输出
Help on function wrapper in module __main__: wrapper(*args, **kwargs)
greet()
函数被装饰以后,它的元信息变了。元信息告诉我们“它不再是以前的那个greet()
函数,而是被wrapper()
函数取代了”。为了解决这个问题,通常使用内置的装饰器
@functools.wrap
,它会帮助保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)。import functools def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper @my_decorator
def greet(message):
print(message) greet.__name__ # 输出
'greet'
类装饰器
实际上,类也可以作为装饰器。类装饰器主要依赖于函数__call__()
,每当你调用一个类的示例时,函数__call__()
就会被执行一次。
class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs)
@Count
def example():
print("hello world")
example()
# 输出
num of calls is: 1
hello world
example()
# 输出
num of calls is: 2
hello world
我们定义了类 Count,初始化时传入原函数 func()
,而__call__()
函数表示让变量 num_calls 自增 1,然后打印,并且调用原函数。因此,在我们第一次调用函数 example()
时,num_calls 的值是 1,而在第二次调用时,它的值变成了 2
装饰器的应用
身份认证 authenticate
日志记录
输入合理性检查 validation_check
缓存 lru_cache
通常使用缓存装饰器,来包裹这些检查函数,避免其被反复调用,进而提高程序运行效率,比如写成下面这样
@lru_cache
def check(param1, param2, ...) # 检查用户设备类型,版本号等等
...
最新文章
- 【转】MySQL批量SQL插入各种性能优化
- 烂泥:centos6.4服务器添加新硬盘
- linux内存回收 内核参数
- rJava配置
- 通过AOP 实现异常统一管理
- BNUOJ-26580 Software Bugs KMP匹配,维护
- SpeeDO —— 并行深度学习系统
- Web Service 的服务端的引用
- WebApi Gzip(Deflate) 压缩请求数据
- CATransform3D参数的意义
- 第一百节,JavaScript表达式中的运算符
- js字符串 数组处理
- 全球性WannaCry蠕虫勒索病毒感染前后应对措施
- 【.NET Core】docker Jenkins ASP.NET Core自动化部署
- linux yum配置代理
- Druid(新版starter)在SpringBoot下的使用以及优点
- Linux sys_call_table变动检测
- lua 语言笔记
- SiteCore Experience Analytics-体验分析
- 【计算机视觉】KCF算法
热门文章
- Springboot + Freemarker(一)
- Chrome 经典插件
- SpringBoot使用RedisTemplate操作Redis时,key值出现 \xac\xed\x00\x05t\x00\tb
- 怎么在三层架构中使用Quartz.Net开源项目(与数据库交互)
- MATLAB GUI设计(3)
- 【Ubuntu】常用命令汇总,整理ing
- 手工注入——MySQL手工注入实战和分析
- 运行npm安装wepy2踩坑error EEXIST 问题
- Appium:We shut down because no new commands came in
- vue中的js引入图片,使用require相关问题