打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Python装饰器和符号@ | Hom

装饰器 Decorator

在代码运行期间动态增加功能的方式,称之为“装饰器”。装饰器本质是高阶函数, 就是将函数作为参数进行相应运作,最后返回一个闭包代替原有函数. 装饰器本质就是将原函数修饰为一个闭包(一个返回函数).

装饰器在python中在函数/对象方法定义前使用@符号调用. 装饰器可以在函数运行前进行一些预处理, 例如检查类型等.

@dec1@dec2(arg1,arg2)def test(arg):    pass

以上代码等于dec1(dec2(arg1,arg2)(test(arg)))

简单的装饰器及其运行机制

例如:

def log(func):    def wrapper(*args, **kw):        print 'call %s():' % func.__name__        return func(*args, **kw)    return wrapper@logdef now():    print '2015-10-26'    return "done"now()# 实际调用wrapper()#>>> call now()#>>> 2015-10-26

装饰器运行机制

机制就是,调用now()实际调用log(now)() (前面@写法后,实际运行now=log(now)),也就是运行了wrapper(),并把now函数原有参数传递给了wrapper函数. wrapper在运行时,加入了新的处理print 'call %s():' % func.__name__一句, 并运行相应传递参数的func(*args,**kw)并把原有结果返回.

now=log(now) #->now=wrapperresult=now() #->wrapper()>>>call now() #-> wrapper修饰部分>>>2015-10-26 #-> 原函数部分执行部分print result>>>done #-> 原函数的返回部分

所以装饰器机制简单地说就是要:

  1. 将原来函数通过装饰器变成一个传递函数本身的高阶函数(@log部分,now=log(now))
  2. 新的高阶函数要返回一个修饰函数,从而使调用原函数时实际调用该部分. (def wrapper()..return wrapper部分)
  3. 新修饰函数进行相应修饰处理(print语句)后,执行原函数并返回原函数值.

传递参数的装饰器

def log(text):    def decorator(func):        def wrapper(*args, **kw):            print '%s %s():' % (text, func.__name__)            return func(*args, **kw)        return wrapper    return decorator@log('execute')def now():    print '2015-10-26'    return "done"now()#>>> excute now()#>>> 2015-10-26

装饰器本身可以传入参数.不要小看这个传入参数, 传入的参数因为占据了本身装饰器的参数, 所以需要新的一层装饰器来处理原函数. 上述机制:

now=log('execute')(now) #-> now=wrapper#或者可以说f=log('execute')  -> f=decorator#          f(now) -> decorator(now) -> wrapper#          now=wrapperresult=now() #wrapper()

实际now=log('execute')(now)两个参数表就是执行了一次闭包decorator(now).执行该闭包后返回的才是真正的装饰器wrapper.

两层闭包的机制可以保证传递参数给内在的装饰器wrapper.第一层将参数传进行生成第一层闭包对应返回函数,第二层则将该参数继续留给真正的装饰器闭包.

继承原有函数信息

在以上装饰器中, 其实质都是now=wrapper, 此时我们要是输出now.__name__得到的将是装饰器wrapper的名字.可以用wrapper.__name__=func.__name__ 加在装饰器内部进行原函数信息的继承, 也可以使用functools.wraps来实现.

import functoolsdef log(func):    @functools.wraps(func)    def wrapper(*args, **kw):        print 'call %s():' % func.__name__        return func(*args, **kw)    return wrapper

对于带参数的装饰器, 依然将@functools.wraps(func)写在实质装饰器wrapper前面.

其机制:

wrapper=functools.wraps(func)(wrapper) #将原函数func信息给返回函数f=functools.wraps(func), f 闭包含有相应func信息.#用f 返回函数来修饰wrapper, 此时实际可以将wrapper的一些信息替换为原函数

对于很复杂的体系, 需要经常定义一些高阶函数对新函数进行一系列处理, 此时定义装饰器就可以省很多功夫. 但缺点是初学比较难以理解, 要对OOP十分熟悉.

对象方法变对象属性的装饰器@property和@*.setter

该装饰器是python内置的,是类中一个高级用法,作用是将一个方法名变成一个对象属性. 类需要继承于object相应的类.
构建相应@property def prop(self):return self._prop就可以直接obj.prop来将方法变成获取对象属性的调用形式.而相应@prop.setter def prop(self,value): self._prop=value 就可以实现obj.prop=value将方法转为对象属性的赋值.而且好处还可以在此加入属性的值的检查. obj._prop只是相应储存的储存地方,名字也是无限制的.
不定义setter而只定义property的话,该属性就是只读的不能修改的!!

例如:

class Student(object):    @property    def score(self):        return self._score    @score.setter    def score(self, value):        if not isinstance(value, int):            raise ValueError('score must be an integer!')        if value < 0 or value > 100:            raise ValueError('score must between 0 ~ 100!')        self._score = value    @property    def fail(self):        return True if (self.score <60) else False        # (self.score <60) and return True or return Falses = Student()s.score = 60 # OK,实际转化为s.set_score(60)s.score # OK,实际转化为s.get_score()### 60s.score = 9999### Traceback (most recent call last):###   ...### ValueError: score must between 0 ~ 100!s.fail### Falses.fail=True### Traceback (most recent call last)### ...### AttributeError: can't set attribute

本博文已合并到Python语法汇总中, 不再更新.


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
理解 Python 装饰器看这一篇就够了 – 码农网
python中强大的装饰器
python笔记35-装饰器
24、Python之有参装饰器
python装饰器详解
python进阶学习笔记(二)——闭包、装饰器、偏函数
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服