Python decorator装饰器

来源:互联网 发布:淘宝捉猫猫是干嘛的 编辑:程序博客网 时间:2024/06/03 19:01

瞥一眼装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。

装饰器模式介绍

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。何时使用:在不想增加很多子类的情况下扩展类。如何解决:将具体功能职责划分,同时继承装饰者模式。关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。应用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。缺点:多层装饰比较复杂。使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。注意事项:可代替继承。

什么是Python装饰器

Python装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

下面我们以一个示例来一步步深入解释Python装饰器

1.我们来获得一个程序的大概执行时间

我们可以直接把计时逻辑方法”myfunc”内部,但是这样的话,如果要给另一个函数计时,就需要重复计时的逻辑。所以比较好的做法是把计时逻辑放到另一个函数中
这里写图片描述

import timedef dec(func):    start=time.time()    func()    end=time.time()    passedtime=(end-start)*1000    print(passedtime)def myfunc():    print("function start")    time.sleep(1)    print("end of function")dec(myfunc)myfunc()

运行结果:

function startend of function1000.0154972076416function startend of function

但是,上面的做法也有一个问题,就是所有的myfunc调用处都要改为dec(myfunc)

2.下面,做一些改动,来避免计时功能对myfunc函数调用代码的影响
这里写图片描述

import timedef dec(func):    def wrapper():        start=time.time()        func()        end=time.time()        passedtime=(end-start)*1000        print(passedtime)    return wrapperdef myfunc():    print("function start")    time.sleep(1)    print("end of function")print("funciton name is: ",myfunc.__name__) myfunc=dec(myfunc) print("funciton name is: ",myfunc.__name__)myfunc()

运行结果

funciton name is:  myfuncfunciton name is:  wrapperfunction startend of function1000.0152587890625

经过了上面的改动后,一个比较完整的装饰器dec就实现了,装饰器没有影响原来的函数,以及函数调用的代码。例子中值得注意的地方是,Python中一切都是对象,函数也是,所以代码中改变了myfunc对应的函数对象。

3.装饰器语法糖

在Python中,可以使用”@”语法糖来精简装饰器的代码:
这里写图片描述

import timedef dec(func):    def wrapper():        start=time.time()        func()        end=time.time()        passedtime=(end-start)*1000        print(passedtime)    return wrapper@decdef myfunc():    print("function start")    time.sleep(1)    print("end of function")print("funciton name is: ",myfunc.__name__) myfunc()

运行结果

funciton name is:  wrapperfunction startend of function1000.0152587890625

使用了”@”语法糖后,我们就不需要额外代码来给myfunc重新赋值了,其实@dec的本质就是myfunc = dec(myfunc),当认清了这一点后,后面看带参数的装饰器就简单了。

被装饰的函数带参数

对于被装饰函数需要支持参数的情况,我们只要使装饰器的内嵌函数支持同样的签名即可。比如我们的函数是function(a,b),则装饰器就需要改为同样的格式,参数名字可以不一样:wrapper(aa,bb)这里还有一个问题,如果多个函数拥有不同的参数形式,怎么共用同样的装饰器?在Python中,函数可以支持(*args, **kwargs)可变参数,所以装饰器可以通过可变参数形式来实现内嵌函数的签名。

这里写图片描述

带参数的装饰器

装饰器本身也可以支持参数,例如说可以通过装饰器的参数来禁止计时功能通过例子可以看到,如果装饰器本身需要支持参数,那么装饰器就需要多一层的内嵌函数。

这里写图片描述

装饰器调用顺序
装饰器是可以叠加使用的,那么这是就涉及到装饰器调用顺序了。对于Python中的”@”语法糖,装饰器的调用顺序与使用 @ 语法糖声明的顺序相反。

@a@b@cdef f ():

等效于

f = a(b(c(f)))

Python内置装饰器

在Python中有三个内置的装饰器,都是跟class相关的:staticmethod、classmethod 和property。

  • staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用
  • classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)
  • property 是属性的意思,表示可以通过通过类实例直接访问的信息

在Python装饰器中其实涉及到了一个很重要的函数思想‘闭包’,为了更好的理解装饰器,建议大家去学习了解一下闭包。
或者说等我出一博客来介绍一下,等某天吧。

原创粉丝点击