python深入学习--decorator强大的装饰器
2015-04-14 20:10
561 查看
欢迎转载,转载请注明原文地址:/article/8326762.html
一.decorator基础。
最初接触python是在大学毕业进入某一游戏公司后,最开始觉得python不严谨,很不喜欢python这种“简单”的脚本,但是后来,越来越离不开python了,觉得这么灵活方便的语言,简直是程序员的福音,尤其是它的数据结构,他带来了一个“{}” 大括号就能搞定一切的时代。当然python还有很多优秀的特性。现在我们来讲python的特性之一--decorator(装饰器)。
装饰器,顾名思义就是修饰函数或者类的,它把要装饰的函数作为参数,然后在函数体内可以执行很多灵活的操作。这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。跟着装饰器声明的是被修饰的函数,和装饰函数的可选参数。装饰器看起来会是这样:
其解释器会解释成下面这样的语句:
@classmethod就是一个decorator,是python内置的装饰器(还有@staticmethod...)
二.decorator的用法。
1.修饰函数:
decorator修饰函数有几种用法。
1).单个Decorator,不带参数
输出为:
before call method
in func
after call method
以上对于func的调用 跟以下是一样的(注释掉@deco()):
再写的明白点:
call_method = deco(func) #deco这个函数返回call_method
call_method(*args) # 是不是恍然大悟了。
当然,最初的写法是最简单的,它让你每一个调用func()的地方都自动调用了@deco(),然后执行一些额外的操作。比如 print "after call method".当然你可以做你想做的任何事,比如在这里记log,你就不需要边CTRL+C,CTRL+V在每一个调用func的地方加上相同的代码了。
2).单个decorator,带参数。
before call method
in func World!
after call method Hello World!
before call method
in func No World!
after call method Hello No World!
总结:
无参数decorator:把函数名传进去,然后生成一个新的装饰器函数
有参decorator:有参装饰,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰
3).decorator还可以有多个,如下图所示:
只不过,平时项目中极少用到,我也就不讲了。
那么什么是装饰器?
现在我们知道装饰器实际就是函数。我们也知道他们接受函数对象。但它们是怎样处理那些函数的呢?一般说来,当你包装一个函数的时候,你最终会调用它。最棒的是我们能在包装的环境下在合适的时机调用它。我们在执行函数之前,可以运行些预备代码,也可以在执行代码之后做些清理工作。所以当你看见一个装饰器函数的时候,很可能在里面找到这样一些代码,它定义了某个函数并在定义内的某处嵌入了对目标函数的调用或者至少一些引用。从本质上看,这些特征引入了java
开发者称呼之为AOP(Aspect Oriented Programming,面向方面编程)的概念。
你可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:
引入日志
增加计时逻辑来检测性能
给函数加入事务的能力
2.修饰类:
修饰类和修饰函数差不多,修饰类是把@decorator放在class上面,用以修改类的属性
输出:
in init Hello
call func: func
三.项目实践
1.最近项目中用到decorator比较多。其中有修饰类的:
2.用在callback里面,但是callback的参数有的存在,有的还需要经过复杂的操作获取,假如你要经过一个异步的操作,操作回来调用func(requestId,*args),requestId是已知的,但是*args是回调回来才有的,你肯定有地方可以存requestId,然后回调回来,再取值进行func操作,但是使用类似decorator的操作可以简化这一操作:
巧妙的把已有的参数传进去,然后等其他参数回来就可以了。
3.使用decorator来增加参数:
在上一篇lambda的用法 /article/8326766.html 中讲解了用lambda来增加参数的例子。
我们这里用decorator来解决
为什么可以这样?
addBtnClickHandler里面的func其实就是callback,func(widget)就是requestId_callback(*args),widget就是*args,那么我们要做的就是把name传进去,
return func(name,*args),就是调用了onClick(name,widget),明白了吧。
也许你会说,做出来了之后解释,大家都可以解释通,那么做之前怎么想到这么decorator可以满足要求呢,那么我们反着来,怎么设计decorator能增加参数,我们要改变的就是addBtnClickHandler里面的func,现在它只有一个参数,而我们需要两个(或者多个),那么就需要外界传进来,那么怎么传进来能满足要求呢
我们要的不就是这个嘛,func就是onClick,callback = addBtnClickHandler的func,但是我们addBtnClickHandler的参数是固定的,怎么传name进来呢,decorator,对,用它来包裹起来传进来,
一.decorator基础。
最初接触python是在大学毕业进入某一游戏公司后,最开始觉得python不严谨,很不喜欢python这种“简单”的脚本,但是后来,越来越离不开python了,觉得这么灵活方便的语言,简直是程序员的福音,尤其是它的数据结构,他带来了一个“{}” 大括号就能搞定一切的时代。当然python还有很多优秀的特性。现在我们来讲python的特性之一--decorator(装饰器)。
装饰器,顾名思义就是修饰函数或者类的,它把要装饰的函数作为参数,然后在函数体内可以执行很多灵活的操作。这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。跟着装饰器声明的是被修饰的函数,和装饰函数的可选参数。装饰器看起来会是这样:
@decorator() def func(*args): pass func(*args)
其解释器会解释成下面这样的语句:
func = decorator(func) func(*args)其实,写过python的人都接触过@decorator。比如写一个单例类:
class Singleton(object): _instance = None def __init__(self): print "init single" @classmethod def instance(cls): if cls._instance is None: cls._instance = Singleton() return cls._instance def func(self): print "call func"
@classmethod就是一个decorator,是python内置的装饰器(还有@staticmethod...)
class Singleton(object): _instance = None def __init__(self): print "init single" #@classmethod def instance(cls): if cls._instance is None: cls._instance = Singleton() return cls._instance instance = classmethod(instance) def func(self): print "call func" Singleton.instance().func()以上跟这个效果是一样的。只不过却让instance少写了两次。
二.decorator的用法。
1.修饰函数:
decorator修饰函数有几种用法。
1).单个Decorator,不带参数
def deco(func): def call_method(*args): print "before call method" func(*args) print "after call method" return call_method @deco() def func(a,b): print "in func" return a + b func(1,2)
输出为:
before call method
in func
after call method
以上对于func的调用 跟以下是一样的(注释掉@deco()):
func = deco(func) func(1,2)
再写的明白点:
call_method = deco(func) #deco这个函数返回call_method
call_method(*args) # 是不是恍然大悟了。
当然,最初的写法是最简单的,它让你每一个调用func()的地方都自动调用了@deco(),然后执行一些额外的操作。比如 print "after call method".当然你可以做你想做的任何事,比如在这里记log,你就不需要边CTRL+C,CTRL+V在每一个调用func的地方加上相同的代码了。
2).单个decorator,带参数。
def deco(a): def real_deco(func): def call_method(*args): print "before call method" result = a + func(*args) print "after call method ",result return call_method return real_deco @deco("Hello ") def func(name): print "in func ",name return name func("World!") func("No World!")输出为:
before call method
in func World!
after call method Hello World!
before call method
in func No World!
after call method Hello No World!
总结:
无参数decorator:把函数名传进去,然后生成一个新的装饰器函数
有参decorator:有参装饰,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰
3).decorator还可以有多个,如下图所示:
@dec_a @dec_b @dec_c def method(args): pass print "==========" method = dec_a(dec_b(dec_c(method)))
只不过,平时项目中极少用到,我也就不讲了。
那么什么是装饰器?
现在我们知道装饰器实际就是函数。我们也知道他们接受函数对象。但它们是怎样处理那些函数的呢?一般说来,当你包装一个函数的时候,你最终会调用它。最棒的是我们能在包装的环境下在合适的时机调用它。我们在执行函数之前,可以运行些预备代码,也可以在执行代码之后做些清理工作。所以当你看见一个装饰器函数的时候,很可能在里面找到这样一些代码,它定义了某个函数并在定义内的某处嵌入了对目标函数的调用或者至少一些引用。从本质上看,这些特征引入了java
开发者称呼之为AOP(Aspect Oriented Programming,面向方面编程)的概念。
你可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:
引入日志
增加计时逻辑来检测性能
给函数加入事务的能力
2.修饰类:
修饰类和修饰函数差不多,修饰类是把@decorator放在class上面,用以修改类的属性
<span style="font-size:14px;">def func(self): return "func" def deco(kclass): kclass.func = func kclass.name = "Hello" return kclass @deco class test(object): def __init__(self): print "in init",self.name print "call func: ",self.func() test()</span>
输出:
in init Hello
call func: func
三.项目实践
1.最近项目中用到decorator比较多。其中有修饰类的:
def is_persistent(_self): return True def Persistent(klass): """ 类的decorator,用来修饰Entity的子类。如: @Persistent class player(Entity): ... 这样的类才会被序列化到mongodb中 """ klass.is_persistent = is_persistent return klass @Persistent class player(Entity): pass相当于在 player里面定义了一个 is_persistent()的方法。在需要Persistent的地方加上@Persistent就行了,当然也可以在每个需要@Persistent的类里面重写这个方法,但是当对象多的时候,自己也不知道自己写了没有了。
2.用在callback里面,但是callback的参数有的存在,有的还需要经过复杂的操作获取,假如你要经过一个异步的操作,操作回来调用func(requestId,*args),requestId是已知的,但是*args是回调回来才有的,你肯定有地方可以存requestId,然后回调回来,再取值进行func操作,但是使用类似decorator的操作可以简化这一操作:
<span style="font-size:14px;">def request_decorator(requestId, func): """ 传递请求序号参数,用于回调 :param func: :return: """ def requestId_callback(*args): return func(requestId, *args) return requestId_callback callback = request_decorator(requestId, self.call_func) ... args = ... callback(*args)</span>
巧妙的把已有的参数传进去,然后等其他参数回来就可以了。
3.使用decorator来增加参数:
在上一篇lambda的用法 /article/8326766.html 中讲解了用lambda来增加参数的例子。
def addBtnClickHander(btn,func): # 这个是通用接口,不可修改 def hander(): widget = "%s_name"%btn # 根据btn取得 func(widget) return hander def main(): btn = 'btn' name = 'name' addBtnClickHander(btn,lambda widget:onClick(widget,name)) def onClick(widget,name): print "onClick:",widget,name
我们这里用decorator来解决
def request_decorator(func,name): """ 传递请求序号参数,用于回调 :param func: :return: """ def requestId_callback(*args): return func(name,*args) return requestId_callback def main(): btn = 'btn' callback = request_decorator(onClick,'a') addBtnClickHander(btn,callback) def onClick(name,widget): print "onClick:",widget,name
为什么可以这样?
addBtnClickHandler里面的func其实就是callback,func(widget)就是requestId_callback(*args),widget就是*args,那么我们要做的就是把name传进去,
return func(name,*args),就是调用了onClick(name,widget),明白了吧。
也许你会说,做出来了之后解释,大家都可以解释通,那么做之前怎么想到这么decorator可以满足要求呢,那么我们反着来,怎么设计decorator能增加参数,我们要改变的就是addBtnClickHandler里面的func,现在它只有一个参数,而我们需要两个(或者多个),那么就需要外界传进来,那么怎么传进来能满足要求呢
name = 'a'
func = onClick def callback(widget): return func(widget,name)
我们要的不就是这个嘛,func就是onClick,callback = addBtnClickHandler的func,但是我们addBtnClickHandler的参数是固定的,怎么传name进来呢,decorator,对,用它来包裹起来传进来,
def decorator(func,name): def callback(widget): return func(widget,name) return callback就像这样。
相关文章推荐
- 深入学习python(三) 闭包(Decorator)与装饰器(Closure)
- Python深入学习之装饰器
- 深入学习Python中的装饰器使用
- 深入学习Python中的装饰器使用
- 装饰器学习(2)------深入理解Python 装饰器(decorator)
- Python 学习笔记9(装饰器,decorator)
- Python教程学习简记11--Python decorator 装饰器
- Python深入学习之装饰器
- python中的装饰器Decorator用法
- 教小姐姐学习python-S01E22神奇的装饰器
- Python学习之路-初学篇之初识装饰器
- python学习笔记:装饰器2
- 步步为营 .NET 设计模式学习笔记 十四、Decorator(装饰模式)
- Python深入学习之闭包
- Python 学习 - 装饰器
- python深入学习笔记6
- 【Python】学习笔记——-5.4、装饰器
- Python学习笔记之(四)——强大的数组计算 Panda
- python深入学习笔记5-装饰器
- python学习系列之python装饰器基础(6)---装饰器加参数