装饰模式和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()的作用。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 12:05:33

装饰模式和python装饰器的相关文章

深入浅出 Python 装饰器:16 步轻松搞定 Python 装饰器

Python的装饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都很相似--都是想要对一个已有的模块做一些"修饰工作",所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去.但是OO的Decorator简直就是一场恶梦,不信你就去看看wikipedia上的词条

python装饰器简介

在了解装饰器的之前一定要先了解函数作为参数传递, 什么是函数内嵌,请参考我之前写的博客函数简介 python装饰器思想有点类似设计模式的装饰模式, 其意图是动态地给函数对象添加额外的功能.比如像增加日志打印的功能,有点面向切面编程(AOP)的感觉. 装饰器语法 以@开头,接着后面跟着的是装饰器的名字和可选的参数.装饰器语法是一种语法糖. 格式如下 @decomaker(deco_args) def foo(func_opt_args) 可以组合,等价于foo = g(f(foo)) @g @f

5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器

一.什么是装饰器? 实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能. 装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式. 高阶函数+函数嵌套+闭包 = 装饰器 1.1什么是高阶函数? 1.1.1函数接收的参数,包涵一个函数名. 1.1.2 函数的返回值是一个函数名. 其实这两个条件都很好满足,下面就是一个高阶函数的例子. def test1(): print "hamasaki ayumi" def test2(func): return t

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

python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说明一下: 小P闲来无事,随便翻看自己以前写的一些函数,忽然对一个最最最基础的函数起了兴趣: 1 def sum1(): 2 sum = 1 + 2 3 print(sum) 4 sum1() 此时小P想看看这个函数执行用了多长时间,所以写了几句代码插进去了: 1 import time 2 3 def

python装饰器1

第八步:让装饰器带 类 参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # -*- coding:gbk -*- '''示例8: 装饰器带类参数''' class locker:     def __init__(self):         print("locker.__init__() should be not called.")   

Python装饰器由浅入深

装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们以装饰函数为例子介绍其用法.要理解在Python中装饰器的原理,需要一步一步来.本文尽量描述得浅显易懂,从最基础的内容讲起. (注:以下使用Python3.5.1环境) 一.Python的函数相关基础 第一,必须强调的是python是从上往下顺序执行的,而且碰到函数的定义代码块是不会立即执行它的,只

python 装饰器学习(decorator)

最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initial decorator" f() def __call__(self): print "call decorator" @decorator def fun(): print "in the fun" print "after " fun

【转】九步学习python装饰器

本篇日志来自:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 纯转,只字未改.只是为了学习一下装饰器.其实现在也是没有太看明白,对于装饰器我就是用的时候找例子,能蒙对,但是用过之后一段时间就忘了.还是用的少.有空应该好好看一看的,包括闭包.对于各种现代编程语言来说闭包都是很重要的.在这里先谢过原作者,如有侵权请告知. =-=-=-=-=-=-=-=-=-=-一条不怎么华丽的分隔线-=-=-=-=-=-=-=-=-=-= 这

【Python之旅】第四篇(一):Python装饰器

有时候拿到一个程序接口,需要对其进行扩展,但是又不能修改原来接口的源代码,这时候就需要使用装饰器了. 有下面一个小程序,假如是别人提供给我们的调用接口: import time def sayHi():         time.sleep(1)         print 'Hello, I am xpleaf.' 一般情况下,如果想要计算该程序的执行时间(因为有可能要对该接口进行某些性能上的测试),就需要把以上接口修改为下面这样,同时执行一下: 程序代码: import time def s