基本概念

具体概念请先看之前的文章 理解装饰器

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理, 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("")
def foo4(a, b=2):
print "Content" foo4(1, b=3)

  实际上此时foo3= decorator_with_params(arg_of_decorator)(foo4)

内置装饰器

内置的装饰器有三个: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

转自:http://blog.csdn.net/wklken/article/details/8118942

参考:http://blog.csdn.net/dreamcoding/article/details/8611578

Python-装饰器进阶的更多相关文章

  1. (转)python装饰器进阶一

    Python装饰器进阶之一 先看例子 网上有很多装饰器的文章,上来说半天也没让人看明白装饰器到底是个什么,究竟有什么用,我们直接来看几个例子. Python递归求斐波那契数列 def fibonacc ...

  2. Python装饰器进阶

    装饰器进阶 现在,我们已经明白了装饰器的原理.接下来,我们还有很多事情需要搞清楚.比如:装饰带参数的函数.多个装饰器同时装饰一个函数.带参数的装饰器和类装饰器. 装饰带参数函数 def foo(fun ...

  3. (转)python装饰器二

    Python装饰器进阶之二 保存被装饰方法的元数据 什么是方法的元数据 举个栗子 def hello(): print('Hello, World.') print(dir(hello)) 结果如下: ...

  4. Python函数--装饰器进阶

    开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封 ...

  5. day 12 - 1 装饰器进阶

    装饰器进阶 装饰器的简单回顾 装饰器开发原则:开放封闭原则装饰器的作用:在不改变原函数的调用方式的情况下,在函数的前后添加功能装饰器的本质:闭包函数 装饰器的模式 def wrapper(func): ...

  6. Python—装饰器详解

    装饰器:(语法糖) 本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式   原则: 1.不能修改被装饰函数的源代码 2.不能修改被装饰函数的调用方式 3.函数的返回值也不变 这两点简而言 ...

  7. day4之装饰器进阶、生成器迭代器

    装饰器进阶 带参数的装饰器 # 某一种情况# 500个函数加装饰器, 加完后不想再加这个装饰器, 再过一个季度,又想加上去# 你可以设计你的装饰器,来确认是否执行 # 第一种情况 # 想要500个函数 ...

  8. 五分钟学会Python装饰器,看完面试不再慌

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第12篇文章,我们来看看Python装饰器. 一段囧事 差不多五年前面试的时候,我就领教过它的重要性.那时候我Pyt ...

  9. Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案

    本文为霍格沃兹测试学院学员学习笔记. Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能.装饰器本质是一种返回值也是函数的函数,可以称之为“函数的函数”. ...

  10. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

随机推荐

  1. AGC 016 C - +/- Rectangle

    题面在这里! 结合了贪心的构造真是妙啊2333 一开始推式子发现 权是被多少个w*h矩形覆盖到的时候 带权和 <0 ,权都是1的时候带权和 >0,也就是说被矩形覆盖的多的我们要让它尽量小. ...

  2. 【计算几何】【极角排序】【二分】Petrozavodsk Summer Training Camp 2016 Day 6: Warsaw U Contest, XVI Open Cup Onsite, Sunday, August 28, 2016 Problem J. Triangles

    平面上给你n(不超过2000)个点,问你能构成多少个面积在[A,B]之间的Rt三角形. 枚举每个点作为直角顶点,对其他点极角排序,同方向的按长度排序,然后依次枚举每个向量,与其对应的另一条直角边是单调 ...

  3. 【CCpp程序设计2017】推箱子游戏

    我的还……支持撤销!用链表实现! 题目:推箱子小游戏(基于console) 功能要求: 将p09迷宫游戏改造为“推箱子”游戏: 在地图中增加箱子.箱子目标位置等图形: 当玩家将所有箱子归位,则显示玩家 ...

  4. [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...

  5. AIM Tech Round (Div. 1) D. Birthday 数学 暴力

    D. Birthday 题目连接: http://www.codeforces.com/contest/623/problem/D Description A MIPT student named M ...

  6. xcode在调试时无法查看变量值

    现象:在xcode中调试程序的时候,无论是鼠标指在变量上,还是在gdb中po命令都看不到内存中变量的值. 解决办法:在Project的Build中把 Optimization Level 设置成 No ...

  7. javacript总结

    前端js总结 //getElementById函数 function $(id){ return document.getElementById(id); } //随机函数不包max //Math.f ...

  8. 如何使用 DBCC MEMORYSTATUS 命令来监视 SQL Server 2005 中的内存使用情况

    https://technet.microsoft.com/en-us/solutionaccelerators/dd537566.aspx 注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完 ...

  9. MySQL优化之如何了解SQL的执行频率

    http://www.jb51.net/article/50180.htm show [session|global] status 可以根据需要加上参数“ session ”或者“ global ” ...

  10. Dockerfile减少构建镜像大小的方法

    这几天基于Dockerfile构建应用需要的特殊的镜像,比如Nginx需要add很多module的,就需要在镜像内编译和做build. 通过Dockerfile构建镜像时,很容易把镜像构建得很大. 从 ...