python 进阶篇 函数装饰器和类装饰器
函数装饰器
简单装饰器
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, ...) # 检查用户设备类型,版本号等等
...
python 进阶篇 函数装饰器和类装饰器的更多相关文章
- python进阶篇
python进阶篇 import 导入模块 sys.path:获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到. import sys ...
- Python进阶(十四)----空间角度研究类,类与类之间的关系
Python进阶(十四)----空间角度研究类,类与类之间的关系 一丶从空间角度研究类 对象操作对象属性 class A(): address = '沙河' def __init__(self, na ...
- Python进阶(二)----函数参数,作用域
Python进阶(二)----函数参数,作用域 一丶形参角度:*args,动态位置传参,**kwargs,动态关键字传参 *args: 动态位置参数. 在函数定义时, * 将实参角度的位置参数聚合 ...
- typescript装饰器定义 类装饰器 属性装饰器 装饰器工厂
/* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...
- Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器
Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器 一丶关键字:global,nonlocal global 声明全局变量: 1. 可以在局部作用域声明一 ...
- Python进阶(一)----函数
Python进阶(一)----函数初识 一丶函数的初识 什么函数: 函数是以功能为导向.一个函数封装一个功能 函数的优点: 1.减少代码的重复性, 2.增强了代码的可读性 二丶函数的结构 ...
- Python入门篇-函数、参数及参数解构
Python入门篇-函数.参数及参数解构 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.函数概述 1>.函数的作用即分类 函数 数学定义:y=f(x) ,y是x的函数,x ...
- Java类载入器(一)——类载入器层次与模型
类载入器 虚拟机设计团队把类载入阶段中的"通过一个类的全限定名来获取描写叙述此类的二进制字节流"这个动作放到Java虚拟机外部去实现.以便让应用程序自己决定怎样去获取所须要的类 ...
- python 装饰器(五):装饰器实例(二)类装饰器(类装饰器装饰函数)
回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文). 那么用类来实现也是也可以的.我们可以让类的构造函数__init__()接受一个函 ...
随机推荐
- 百道Python面试题实现,搞定Python编程就靠它
对于一般的机器学习求职者而言,最基础的就是掌握 Python 编程技巧,随后才是相关算法或知识点的掌握.在这篇文章中,我们将介绍一个 Python 练习题项目,它从算法练习题到机试实战题提供了众多问题 ...
- redis吊锤面试官,这篇足够了!
原理篇 redis 时单线程的为什么还能那么快? 数据都在内存中,运算都是内存级别的运算. redis既然是单线程的为什么能处理那么多的并发数? 多路复用,操作系统时间轮训epoll 函数作为选择器, ...
- Linux下的ngnix安装与启动
Linux安装Nginx 1.安装gcc gcc-c++(如新环境,未安装请先安装)$ yum install -y gcc gcc-c++2.安装wget$ yum -y install wget ...
- [noip2016]蚯蚓<单调队列+模拟>
题目链接:https://vijos.org/p/2007 题目链接:https://www.luogu.org/problem/show?pid=2827#sub 说实话当两个网站给出AC后,我很感 ...
- Openresty+Lua+Kafka实现日志实时采集
简介 在很多数据采集场景下,Flume作为一个高性能采集日志的工具,相信大家都知道它.许多人想起Flume这个组件能联想到的大多数都是Flume跟Kafka相结合进行日志的采集,这种方案有很多他的优点 ...
- vuex知识要点梳理
该内容为个人总结,请勿喷. 欢迎各位大神前来指点.
- @Configuration和@Bean 配置类注入
@Configuration和@Bean 1. 概述 @Configuration 注解标记在类上, 就像下面的配置文件. 我们将该类成为配置类. <?xml version="1.0 ...
- 掌握使用gitlab ci构建Android包的正确方式
最近公司在做移动端的项目,自然而然的需要搭建打包的环境.本来计划用Jenkins的,但是发现在gitlab上创建完项目后,提示去配置pipeline,于是决定用gitlab去尝试下,毕竟我觉得Jenk ...
- testng.xml配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "htt ...
- JSP 简介(转载)
什么是Java Server Pages? JSP全称Java Server Pages,是一种动态网页开发技术.它使用JSP标签在HTML网页中插入Java代码.标签通常以<%开头以%> ...