装饰器和装饰模式

先给出两者的定义:

- 装饰器:装饰器是一个非常著名的设计模式,常常被用于有切面需求的场景。较为经典的有插入日志、性能測试、事务处理等。

装饰器是解决这类问题的绝佳设计。有了装饰器,我们就能够抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲。装饰器的作用就是为已经存在的对象加入额外的功能。

- 装饰模式:在不必改变原类文件和使用继承的情况下。动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

装饰器是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装饰器的更多相关文章

  1. python装饰器2

    装饰模式有很多经典的使用场景,例如插入日志.性能测试.事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的.下面就一步步看看Python中的装饰器. 一个简单 ...

  2. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  3. python装饰器通俗易懂的解释!

    1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...

  4. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  5. python 装饰器修改调整函数参数

    简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...

  6. python 装饰器学习(decorator)

    最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...

  7. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  8. 关于python装饰器(Decorators)最底层理解的一句话

    一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...

  9. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

随机推荐

  1. Android_L(64bit) 模拟器配置及创建项目

    Android L可能就是Android 5.0.随之而来的还有Android Watch. Android TV. 而据说在10月中旬也就是15号Google的公布会上应该会推出Nexus 6和Ne ...

  2. Onvif开发之代码框架生成篇

    看了前一篇的ONVIF的简单介绍应该对它的基本使用都有了一些基本的了解了吧!下面我讲一步分解向大家介绍下如何通过gsoap生成需要的代码,以及代码中需要注意的问题[基于Linux平台 C开发] 生成O ...

  3. 7.Web Service 调用天气代码

    1. 2500多个城市天气预报 WEB服务公用事业 Endpoint:http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx Disco: ...

  4. 2.Brackets安装及常用插件安装

    转自:https://blog.csdn.net/autumn20080101/article/details/53171326 Brackets 是一个免费.开源且跨平台的 HTML/CSS/Jav ...

  5. Multidex实现简要分析

    1.Multidex的产生 在android5.0之前,每一个android应用中只会含有一个dex文件,但是因为Android系统本身的BUG,使得这个dex的方法数量被限制在65535之内,这就是 ...

  6. C# 开发 —— 数组类对象接口

    数组类型是从抽象基类 Array 派生的引用类型,通过new运算符创建数组并将数组元素初始化为他们的默认值 一维数组 type[] arrayname; 数组的长度不是声明的一部分,而且数组必须在访问 ...

  7. java 第三方库

    转载自http://www.cnblogs.com/lucus-jia/p/3483511.html java 第三方库   总结一下常用的java第三方库,方便查询和使用,欢迎补充. 1.核心库 A ...

  8. DG应用日志相关操作

    应用archive log: recover managed standby database disconnect;     应用redo logfile: recover managed stan ...

  9. Laravel输出sql语句

    $queries = DB::getQueryLog();

  10. STM32之串口IAP更新升级

    一.IAP简介 IAP是应用编程,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级,后续产品发布后,更新程序我只需要把.bin文件通过串口发送给芯片就可以执行更 新,很方 ...