设为首页 收藏本站
查看: 1302|回复: 0

[经验分享] Python-进阶-装饰器小结

[复制链接]

尚未签到

发表于 2018-8-14 10:48:36 | 显示全部楼层 |阅读模式
基本概念
  具体概念自己google
  装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理, Web权限校验, Cache等。
  很有名的例子,就是咖啡,加糖的咖啡,加牛奶的咖啡。
  本质上,还是咖啡,只是在原有的东西上,做了“装饰”,使之附加一些功能或特性。
  例如记录日志,需要对某些函数进行记录
  笨的办法,每个函数加入代码,如果代码变了,就悲催了
  装饰器的办法,定义一个专门日志记录的装饰器,对需要的函数进行装饰,搞定
优点
  抽离出大量函数中与函数功能本身无关的雷同代码并继续重用
  即,可以将函数“修饰”为完全不同的行为,可以有效的将业务逻辑正交分解,如用于将权限和身份验证从业务中独立出来
  概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能
Python中的装饰器
  在Python中,装饰器实现是十分方便的
  原因是:函数可以被扔来扔去。
  函数作为一个对象:
A.可以被赋值给其他变量,可以作为返回值  

  
B.可以被定义在另外一个函数内
  def:
  装饰器是一个函数,一个用来包装函数的函数,装饰器在函数申明完成的时候被调用,调用之后返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问(申明的函数被换成一个被装饰器装饰过后的函数)
  当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。
  由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现
分类:
  装饰器分为无参数decorator,有参数decorator
* 无参数decorator  

  
生成一个新的装饰器函数
  

  
* 有参decorator
  

  
有参装饰,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰
  装饰器有参/无参,函数有参/无参,组合共4种
具体定义:
  decorator方法
  A.把要装饰的方法作为输入参数,
  B.在函数体内可以进行任意的操作(可以想象其中蕴含的威力强大,会有很多应用场景),
  C.只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数, 或者是一个新函数)
无参数装饰器 – 包装无参数函数
  不需要针对参数进行处理和优化
def decorator(func):  
    print "hello"
  
return func
  
@decorator
  
def foo():
  
    pass
  
foo()
  foo()
  等价于:
foo = decorator(foo)  
foo()
无参数装饰器 – 包装带参数函数
def decorator_func_args(func):  
def handle_args(*args, **kwargs): #处理传入函数的参数
  
    print "begin"
  
func(*args,**kwargs)   #函数调用
  
    print "end"
  
    return handle_args
  
@decorator_func_args
  
def foo2(a,b=2):
  
    print a,b
  
foo2(1)
  foo2(1)
  等价于
foo2 = decorator_func_args(foo2)  
foo2(1)
带参数装饰器 – 包装无参数函数
def decorator_with_params(arg_of_decorator):#这里是装饰器的参数  
    print arg_of_decorator
  
#最终被返回的函数
  
    def newDecorator(func):
  
        print func
  
        return func
  
    return newDecorator
  
@decorator_with_params("deco_args")
  
def foo3():
  
    pass
  
foo3()
  与前面的不同在于:比上一层多了一层封装,先传递参数,再传递函数名
  第一个函数decomaker是装饰函数,它的参数是用来加强“加强装饰”的。由于此函数并非被装饰的函数对象,所以在内部必须至少创建一个接受被装饰函数的函数,然后返回这个对象(实际上此时foo3=decorator_with_params(arg_of_decorator)(foo3))
带参数装饰器– 包装带参数函数
def decorator_whith_params_and_func_args(arg_of_decorator):  
    def handle_func(func):
  
        def handle_args(*args,**kwargs):
  
            print "begin"
  
            func(*args,**kwargs)
  
            print "end"
  
            print arg_of_decorator,func,args,kwargs
  
        return handle_args
  
    return handle_func
  
@decorator_whith_params_and_func_args("123")
  
def foo4(a,b=2):
  
    print "Content"foo4(1,b=3)
内置装饰器
  内置的装饰器有三个:staticmethod,classmethod, property
class A():  
    @staticmethod
  
    def test_static():
  
        print "static"
  
    def test_normal(self):
  
        print "normal"
  
    @classmethod
  
    def test_class(cls):
  
        print "class",cls
  
a = A()
  
A.test_static()
  
a.test_static()
  
a.test_normal()
  
a.test_class()
  结果:
static  
static
  
normal
  
class __main__.A
  A.test_static
  staticmethod 类中定义的实例方法变成静态方法
  基本上和一个全局函数差不多(不需要传入self,只有一般的参数),只不过可以通过类或类的实例对象来调用,不会隐式地传入任何参数。
  类似于静态语言中的静态方法
  B.test_normal
  普通对象方法:
  普通对象方法至少需要一个self参数,代表类对象实例
  C.test_class
  类中定义的实例方法变成类方法
  classmethod需要传入类对象,可以通过实例和类对象进行调用。
  是和一个class相关的方法,可以通过类或类实例调用,并将该class对象(不是class的实例对象)隐式地当作第一个参数传入。
  就这种方法可能会
比较奇怪一点,不过只要你搞清楚了python里class也是个真实地存在于内存中的对象,而不是静态语言中只存在于编译期间的类型,就好办了。正常的方法就是和一个类的实例对象相关的方法,通过类实例对象进行调用,并将该实例对象隐式地作为第一个参数传入,这个也和其它语言比较像。
  D.区别
  staticmethod,classmethod相当于全局方法,一般用在抽象类或父类中。一般与具体的类无关。
  类方法需要额外的类变量cls,当有子类继承时,调用类方法传入的类变量cls是子类,而不是父类。
  类方法和静态方法都可以通过类对象和类的实例对象访问
  定义方式,传入的参数,调用方式都不相同。
  E.property
  对类属性的操作,类似于java中定义getter/setter
class B():  
    def __init__(self):
  
        self.__prop = 1
  
    @property
  
    def prop(self):
  
        print "call get"
  
    return self.__prop
  
    @prop.setter
  
    def prop(self,value):
  
        print "call set"
  
        self.__prop = value
  
    @prop.deleter
  
    def prop(self):
  
        print "call del"
  
        del self.__prop
其他
  A.装饰器的顺序很重要,需要注意
@A  
@B
  
@C
  
def f():
  等价于
f = A(B(C(f)))  B.decorator的作用对象可以是模块级的方法或者类方法
  C.functools模块提供了两个装饰器。
  这个模块是Python 2.5后新增的。
  functools.wraps(func)
  total_ordering(cls)
  这个具体自己去看吧,后续用到了再补充
一个简单例子
  通过一个变量,控制调用函数时是否统计时间
#!/usr/bin/env python  
# -*- coding:utf-8 -*-
  
#@author:wklken@yeah.net、
  
#@version: a test of decorator
  
#@date:20121027
  
#@desc:just a test
  
import logging
  
from time import time
  
logger = logging.getLogger()
  
logger.setLevel(logging.DEBUG)is_debug = True
  
def count_time(is_debug):
  
    def handle_func(func):
  
        def handle_args(*args,**kwargs):
  
            if is_debug:
  
                begin = time()
  
                func(*args,**kwargs)
  
                logging.debug("[" + func.__name__ + "] -> " + str(time() - begin))
  
            else:
  
                func(*args,**kwargs)
  
        return handle_args
  
    return handle_func
  
def pr():
  
    for i in range(1,1000000):
  
        i = i * 2
  
        print "hello world"、
  
def test():
  
    pr()
  
@count_time(is_debug)
  
def test2():
  
    pr()
  
@count_time(False)
  
def test3():
  
    pr()
  
if __name__ == "__main__":
  
    test()
  
    test2()
  
    test3()
  结果:
hello world  
hello world
  
DEBUG:root:[test2] -> 0.0748538970947
  
hello world
  The end!
  转自: http://wklken.sinaapp.com/

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-551546-1-1.html 上篇帖子: python isinstance、isalnum函数用法 下篇帖子: PEP8 Python 编码规范整理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表