博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
理解Python装饰器(Decorator)
阅读量:6936 次
发布时间:2019-06-27

本文共 3901 字,大约阅读时间需要 13 分钟。


date: 2017-04-14 00:06:46

Python的装饰器,顾名思义就是可以为已有的函数或对象起到装饰的作用,使得达到代码重用的目的。

从一个简单的例子出发

这个例子中我们已经拥有了若干个独立的函数。

#! python 2# coding: utf-8def a():  print("a")def b():  print("b")def c():  print("c")a()b()c()

输出结果是

abc

而我们想要给这三个函数都加上打印当前日期的功能,倘若没有学习装饰器,那我们可能要为每一个函数都添加一行语句。

#! python 2# coding: utf-8import timedef a():  print(time.asctime( time.localtime(time.time())))  print("a")def b():  print(time.asctime( time.localtime(time.time())))  print("b")def c():  print(time.asctime( time.localtime(time.time())))  print("c")a()b()c()

这样看来需要添加的代码量似乎并不多,但如果需要被添加此功能的已经写好的模块已经有上百上千甚至上万?这样写岂不是过于繁杂,而有了装饰器,我们则可以像下面这样。

#! python3# coding: utf-8import time# return timedef rtime(func):  def wrapper():    print(time.asctime( time.localtime(time.time())))    return func()  return wrapper@rtimedef a():  print("a")@rtimedef b():  print("b")@rtimedef c():  print("c")a()b()c()

怎么样,是不是简洁明了了很多。

更加通用一点的装饰器

可以看到,上面的三个函数都没有接受参数,那如果rtime去装饰含有参数的函数会怎样呢?

#! python3# coding: utf-8import time# return timedef rtime(func):  def wrapper():    print(time.asctime(time.localtime(time.time())))    return func()  return wrapper@rtimedef d(a):  print(a)d(1)

显然,d函数包含了一个参数d,如果此时运行的话,则会出现报错

TypeError: wrapper() takes no arguments (1 given)

为了可以使得装饰器更加通用,我们可以像下面这样写:

#! python3# coding: utf-8import time# return timedef rtime(func):  def wrapper(*args, **kwargs):    print(time.asctime(time.localtime(time.time())))    return func(*args, **kwargs)  return wrapper@rtimedef d(a):  print(a)d(1)

可以看到,其中添加了*args和**kwargs,Python提供了可变参数*args和关键字参数**kwargs用于处理未知数量参数,这样就能解决被修饰函数中带参数得问题。

那如果是装饰器本身想要带上参数呢,先记住这样一句话:本身需要支持参数得装饰器需要多一层的内嵌函数。下面看具体的代码实现:

#! python3# coding: utf-8import time# return timedef rtime(x):    print(x)    def wrapper(func):        def inner_wrapper(*args, **kwargs):            print(time.asctime(time.localtime(time.time())))            return func(*args, **kwargs)        return inner_wrapper    return wrapper@rtime(1) # x = 1def d(a):    print(a)d(2)

输出结果为

1Wed Apr 12 20:43:54 20172

调用多个装饰器

python的装饰器支持多次调用,且调用的顺序与在被装饰函数前声明装饰器的顺序相反,如若想先调用装饰器demo1和demo2,则装饰时应先@demo2再@demo1。

类实现的装饰器

若想要通过类来实现装饰器,则需要修改类的构造函数__init__()并重载__call__()函数。下面是一个简单的例子:

#! python3# coding: utf-8import time# return timedef rtime(x):    print(x)    def wrapper(func):        def inner_wrapper(*args, **kwargs):            print(time.asctime(time.localtime(time.time())))            return func(*args, **kwargs)        return inner_wrapper    return wrapper# return time 不带参数的类实现class rtime1(object):    def __init__(self, func):        self.func = func        def __call__(self, *args, **kwargs):        print(time.asctime(time.localtime(time.time())))        return self.func(*args, **kwargs)# return time 带参数的类实现class rtime2(object):    def __init__(self, x):        self.x = x        def __call__(self, func):        def wrapper(*args, **kwargs):            print(self.x)            print(time.asctime(time.localtime(time.time())))            return func(*args, **kwargs)        return wrapper@rtime(1)def d(a):    print(a)@rtime1def e(a):    print(a)@rtime2(2)def f(a):    print(a)d(3)e(4)f(5)

输出结果为

1Thu Apr 13 11:32:22 20173Thu Apr 13 11:32:22 201742Thu Apr 13 11:32:22 20175

Python内置装饰器

@property

内置装饰器property可以帮助我们为一个class写入属性

#! python3# coding: utf-8import timeclass test(object):        @property    def x(self):        return self._x        @x.setter    def x(self, value):        self._x = value    @x.deleter    def x(self):        del self._xtemp = test()temp.x = 1print temp.x

输出结果为1,想必会有人疑惑为什么要这样写入属性,如果没有这样绑定属性直接将temp.x赋值的话,则属性x是不可控的,而通过property绑定属性之后,则可以在setter设定的时候添加对范围的判断,使得属性可控,property还有getter装饰器,不过getter装饰器和不带getter的属性装饰器效果一样。

@staticmethod & @classmethod

通过staticmethod和classmethod装饰器可以使得我们在不实例化类的情况下直接调用类中的方法:class_name.method()即可直接调用。

那么staticmethod和classmethod又有什么区别呢?
@staticmethod不需要表示实例的self和自身类的cls参数,也就是说可不传递参数。
@classmethod的第一个参数必须有且必须是表示自身类的cls参数。

转载于:https://www.cnblogs.com/Mu001999/p/8134249.html

你可能感兴趣的文章
24个精美的抽象背景图片素材免费下载
查看>>
ASP.NET MVC 实现二级域名
查看>>
Effective java笔记8--序列化
查看>>
nutch getOutLinks 外链的处理
查看>>
由ConcurrentLinkedQueue扯到线程安全 待整理
查看>>
Android 屏幕保护开发思路
查看>>
ffmpeg参数解释--中文详细
查看>>
算法题——投篮比赛获胜概率问题
查看>>
系统特殊路径一览
查看>>
由比特币所想到的关于货币的深入思考
查看>>
Linux下的shell与make
查看>>
我也来说说DDD~大话目录
查看>>
一致性环Hash算法.NET实现
查看>>
禁止复制 + 锁右键 + 禁止全选(兼容IE Chrome等)
查看>>
iOS:根据系统类型加载不同的xib
查看>>
JS仿淘宝详情页菜单条智能定位效果
查看>>
DELL 720XD和R820玩赏
查看>>
create_project.py报错问题,建议用回python2.7
查看>>
与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器...
查看>>
android UI进阶之实现listview的分页加载
查看>>