基本概念

具体概念自己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():passfoo()

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, bfoo2(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 funcreturn funcreturn 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,kwargsreturn handle_argsreturn 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():@staticmethoddef test_static():print "static"def test_normal(self):print "normal"@classmethoddef test_class(cls):print "class", clsa = 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@propertydef prop(self):print "call get"return self.__prop@prop.setterdef prop(self, value):print "call set"self.__prop = value@prop.deleterdef 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 testimport loggingfrom time import timelogger = logging.getLogger()
logger.setLevel(logging.DEBUG)
is_debug = Truedef 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_argsreturn handle_funcdef pr():for i in range(1,1000000):i = i * 2print "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!

Python-decorator装饰器小结相关推荐

  1. 廖雪峰python教程学习:装饰器@小结

    装饰器@小结 廖雪峰老师的python教程 在代码运行期间动态增加功能的方式,称为装饰器 本质上,装饰器是一个可以返回函数的高阶函数 最基本的可以定义如下: def log(func):@functo ...

  2. Python 中的闭包、匿名函数、decorator 装饰器与python的偏函数

    Python中的闭包 def calc_sum(lst):def lazy_sum():return sum(lst)return lazy_sum 像这种内层函数引用了外层函数的变量(参数也算变量) ...

  3. Python的装饰器decorator

    Python的装饰器decorator 作者:王大为 时间:2016-10-19 一.装饰器的本质 本质:装饰器本身就是一个函数,高阶函数+嵌套函数==>装饰器 原则: * 1.不能修改被装饰函 ...

  4. Python中的decorator装饰器使用方法

    装饰器的运用是Python编程中的一项高级技巧,这里由浅入深,整理了12步入门Python中的decorator装饰器使用方法,需要的朋友可以参考下 装饰器(decorator)是一种高级Python ...

  5. Python的装饰器

    详解Python的装饰器 本文源码 https://github.com/tobyqin/python_decorator Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都 ...

  6. 《是碰巧还是执着?python所阅读的每一场知识点,唯一的共同点就是——参赛选手中,有详解Python的装饰器!》

    Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...

  7. 详解Python的装饰器

    详解Python的装饰器 Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye( ...

  8. python中装饰器的作用_Python装饰器详解,详细介绍它的应用场景

    装饰器的应用场景附加功能 数据的清理或添加:函数参数类型验证 @require_ints 类似请求前拦截数据格式转换 将函数返回字典改为 JSON/YAML 类似响应后篡改为函数提供额外的数据 moc ...

  9. 关于Python的装饰器(1)

    Python的装饰器的概念,一直有点微妙.之前在StackOverflow上看过一篇感觉说明的很清楚的介绍: *A decorator must accept a function as an arg ...

  10. python装饰器函数-Python精进-装饰器与函数对象

    本文为<爬着学Python>系列第四篇文章. 从本篇开始,本专栏在顺序更新的基础上,会有不规则的更新. 在Python的学习与运用中,我们迟早会遇到装饰器,这个概念对于初识装饰器的新手来说 ...

最新文章

  1. 启明云端分享| sigmastar SSD201/ SSD202D _OTA升级使用参考
  2. Swoole安装步骤
  3. 【复习资料】设计模式
  4. javafx 遮罩_JavaFX技巧31:遮罩/剪切/ Alpha通道
  5. day10-列表生成式
  6. java中线程调度遵循的原则_深入理解Java多线程核心知识:跳槽面试必备
  7. IDEA和VS code设置默认换行符为LF
  8. 边缘计算ARMNN(一):ARM-ARMNN-ComputeLibrary rk3399 编译配置
  9. oracle在进行跨库访问时,采用dblink实现
  10. Mac osx 技巧
  11. webpack 初学笔记
  12. Q 系列PLC ST 语言编程笔记
  13. Excel中Alt快捷键的用法
  14. 无线路由器的AP、Client、WDS、WISP使用功能图解(清晰明了)
  15. Linux 添加802.11n网卡驱动
  16. php 微信公共平台开发
  17. 在线语音合成 Java SDK 文档(科大讯飞)
  18. [经典面试题]实现memcpy库函数
  19. 利用ArcGIS软件将csv文件转换为shp格式
  20. FITC-PEG-Biotin,荧光素-聚乙二醇-生物素的相关检测

热门文章

  1. 5%精度的电阻值间的倍率,倍数
  2. fail2ban防止暴力破解
  3. C# typeof Gettype is as 拆箱 装箱
  4. 0046算法笔记——【随机化算法】舍伍德随机化思想解决跳跃表问题
  5. ExecuteNonQuery()返回受影响行数不适用select语句
  6. 《面向模式的软件体系结构1--模式系统》读书笔记(2)--- 映像模式
  7. 查看linux系统的性能
  8. PL/SQL不能导入备份文件如何解决
  9. C++游戏开发需要阅读的书籍
  10. Docker镜像制作规范