装饰模式和python装饰器
装饰器和装饰模式
先给出两者的定义:
- 装饰器:装饰器是一个非常著名的设计模式,常常被用于有切面需求的场景。较为经典的有插入日志、性能測试、事务处理等。
装饰器是解决这类问题的绝佳设计。有了装饰器,我们就能够抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲。装饰器的作用就是为已经存在的对象加入额外的功能。
- 装饰模式:在不必改变原类文件和使用继承的情况下。动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰器是python的高级函数应用的一个技巧,能够在不修改对象的前提下增强对象的功能。
这个对象能够是函数,类方法和类属型。看到“装饰”和它的功能,对于设计模式比較熟悉的同学应该会想到装饰模式。假设你如今没有想到装饰器或者对于装饰器没有一个清晰的概念认识,那么就跟我一起来复习一下装饰模式。深入理解装饰模式对于装饰器的理解会非常有帮助。
装饰模式演示样例
这里我们使用java来通过一个简单的场景展示一下装饰模式。
情景:程序员没日没夜的工作能够赚钱,把钱攒起来之后就能够买房买车,迎娶白富美。走上幸福生活。。。
这里我们定义一个能够存钱的接口:CanSaveMoney。程序员类Coder。
public interface CanSaveMoney {
public void save(int money);
}
class Coder implements CanSaveMoney {
private int count = 0;
@Override public void save(int money) {
count += money;
}
}
/××
×存钱的方法
××/
public void saveMoney(CanSaveMoney person, int money) {
person.save(money)
}
情景续:过了一段时间,程序员追到了女神,须要和女神培养感情。
但是我们之前不过留了一个存钱的功能没有取钱的功能,没有问题,程序员都是聪明的,我们存一个负的钱数不就是取钱了麻。
就这样程序员顺利的跟女神培养好了感情。
到了女神管理程序员的收入的时候了,女神识破了程序员的小把戏。如何修复这个漏洞呢?女神是霸道的,女神觉得程序员的一切都是她的,程序员上缴工资卡。一切都经过女神的手。
class Godness implements CanSaveMoney {
private Coder coder;
public Godness(Coder coder) {
this.coder = coder;
}
@Override public void save(int money) {
if (money <= 0) {
throw new RuntimeException("滚犊子");
} else {
coder.save(money);
}
}
}
上面就是使用了装饰模式。在不修改原有类的情况下增强类的某一功能。
python 装饰器
python中装饰器是对装饰模式的一个更宽泛的应用,不只能够应用于类,也能应用于函数。类方法和类属性。灵活利用装饰器能够大大提高你的python开发效率。
简单的装饰器演示样例
以下是一些简单的装饰器演示样例, 展示了你能够在函数调用之前或者之后做一些处理。
import functools
# do something before call
def log(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
print('begin %s()' % fun.__name__)
return fun(*args, **kwargs)
return wrapper
# do something before and after call
def log2(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
print('begin call %s()' % fun.__name__)
f = fun(*args, **kwargs)
print('end call')
return f
return wrapper
# decorator with param
def log_tag(tag):
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('%s %s()' % (tag, func.__name__))
return func(*args, **kwargs)
return wrapper
return log
#装饰器类,适用于须要保存一些多次调用的信息。如函数调用的次数
class LogClass(object):
def __init__(self, f):
self.f = f
self.count = 0
# 复制原函数的属性
for n in set(dir(f)) - set(dir(self)):
setattr(self, n, getattr(f, n))
def __call__(self, *args):
self.count += 1
print('called times: %s' % self.count)
return self.f(*args)
def __repr__(self):
return self.f
@log_tag("execute")
def print_num(n=0):
print('num is %s' % n)
if __name__ == '__main__':
for n in range(1, 4):
print_num(n)
print('%s' % print_num.__name__)
关于@functools.wraps()
@functools.wraps()
是functools模块中一个非常实用的装饰器,它的作用是把原函数的属性拷贝到装饰过的函数中。函数也是对象,所以函数的属性这也概念不难理解,比如你能够使用pirnt('%s' % print_num.__name__)
来打印出函数的名称属性。这里重点解释装饰过的函数并不是原函数。
上面的代码片断最后我们打印出了函数的名称属性。假设我们把装饰器中的@functools.wraps()
这一行凝视掉之后。再运行打印,打印出的结果不会再是print_numm
了。而是wrapper
。弄清晰原因你就理解了@functools.wraps()
的作用。
为什么装饰过的函数的print_num.__name__
改变了?
上面我们使用@log
的形式来使用装饰器装饰函数。这在python里面叫装饰器语法。不使用装饰器语法的的形式是这种
print_num = log(print_num)
print_num(n)
这样我们就理解了为什么装饰过后的函数不再是原来的函数了。上面代码段中装饰器类初始化代码中获取设置原函数属性的作用相似于@functools.wraps()
的作用。
装饰模式和python装饰器的更多相关文章
- python装饰器2
装饰模式有很多经典的使用场景,例如插入日志.性能测试.事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的.下面就一步步看看Python中的装饰器. 一个简单 ...
- 关于python装饰器
关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...
- python装饰器通俗易懂的解释!
1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- python 装饰器修改调整函数参数
简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...
- python 装饰器学习(decorator)
最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...
- Python装饰器详解
python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...
- 关于python装饰器(Decorators)最底层理解的一句话
一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...
- Python装饰器由浅入深
装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...
随机推荐
- SSH远程快速登录Linux
SSH远程快速登录Linux 使用SSH管理linux服务器,通常要使用ssh,然后输入用户,密码,其实只要配置一个文件就可以方便登录.假设要登录server域名是www.interne ...
- Kinect开发 —— 基础知识
转自:http://www.cnblogs.com/yangecnu/archive/2012/04/02/KinectSDK_Application_Fundamentals_Part2.html ...
- RPC简易学习
0.RPC简介 RPC, 英文全称:Remote Process Call. 中文全称:远程过程调用. 客户端通过网络请求调用远程服务端对外暴露服务.常用的两种RPC协议:TCP.HTTP. ...
- Linux下关机命令的区别 (halt,poweroff,reboot,shutdown,init)
1.shutdown shutdown命令安全地将系统关机. 而在系统关机前使用shutdown命令﹐系统管理员会通知所有登录的用户系统将要关闭.并且login指令会被冻结﹐即新的用户不能再登录 ...
- ZJU 2425 Inversion
Inversion Time Limit: 2000ms Memory Limit: 65536KB This problem will be judged on ZJU. Original ID: ...
- Springboot2.0访问Redis集群
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作高性能的key-value数据库.缓存和消息中间件,掌握它是程序员的必备技能,下面是一个springboot访问redis的 ...
- 洛谷 P2108 学英语
P2108 学英语 题目描述 为了适应紧张的大学学习生活,小Z发愤图强开始复习巩固英语. 由于小Z对数学比较有好感,他首先复习了数词.小Z花了一整天的时间,终于把关于基数词的知识都搞懂了.于是小Z非常 ...
- shell date 命令说明
shell date 命令说明 使用方法:date [选项]... [+格式] 或:date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] 以给定的格式 ...
- 一个统一将数据转换为JSON的方法
这是我得方法: 导包: import net.sf.json.JSONArray; import net.sf.json.JSONObject; public void writeJson(Objec ...
- BZOJ3282: Tree (LCT模板)
Description 给定N个点以及每个点的权值,要你处理接下来的M个操作. 操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和 ...