简介
每次我们看到decorator的时候,如果有java背景的人会潜意识的想到decorator pattern。的确,decorator pattern是一种将一些功能叠加到一个类上的一种手法。在java里我们需要费一些手脚才能把这些东西给叠加起来。那么在python里面呢?decorator的作用和意义仅仅是在于这个pattern么?我们可以来详细的看看。
python decorator的定义和应用
在python里定义decorator主要有两种方式,一种是基于方法的方式,一种是基于类定义的方式,他们定义的形式稍微有一些不同,不过都基于同样的思想。在看decorator的具体定义之前,我们先看看python里对待方法的处理方式。
函数的定义和传递
我们来看下面的代码:
def outer(): def inner(): print("Inside inner function.") return inner
这部分代码比较简单,就是在一个outer的方法里定义了一个inner的方法。然后比较奇怪的是,outer方法返回的是inner方法。这就是一个看来很难理解的地方。在python里,方法/函数都可以作为一个类似于普通对象参数进行传递。这是很多函数式编程语言里常用的思想,在后续的文章里还会进一步讨论。所以这里outer方法里定义了inner方法,然后它返回了inner方法。那么我们该怎么使用它们呢?
这是使用这些代码的典型交互结果:
>>> from outer import outer >>> foo = outer() >>> foo() Inside inner function.
这里,我们将outer()方法的结果作为一个对象赋值给foo。按照前面的理解,实际上就是inner方法。然后我们用foo()这样的方式调用了inner方法。
前面的这个示例说明了我们可以将函数作为一个对象当作返回结果。实际上,我们也可以将函数作为方法的参数来传递,我们再看另外一个示例:
def outer(func): def inner(): print("Inner function before func execution.") return func() return inner
这里outer方法传进来了一个func,在inner方法里我们执行了func()。可以说,这个func必须是一个可以执行的对象,比如实现__call__()方法的对象或者就是一个方法。
我们该怎么使用前面这段代码呢?我们看下面这部分:
>>> def counter(): ... print("counter method execution") ... >>> foo = outer(counter) >>> foo() Inner function before func execution. counter method execution
这里我们定义了一个counter方法。然后将counter方法作为参数传递给outer方法。然后我们可以将outer方法调用的结果再赋值给foo,然后再把foo当作一个方法来调用。
嗯,经过这一通折腾,我们就知道了在python里,可以定义一个函数,然后将它当成一个普通的对象参数来传递或者返回。这个参数在使用的时候就和调用普通方法一样。这种手法看起来比较怪,不过还是好理解。这些东西和decorator有什么关系呢?其实有了这一步,我们基于函数的方式来定义decorator就只差一点了。
基于函数的定义
在前面那一部分,我们后面定义的示例里将一个函数传递到一个函数里,然后在inner()方法里做了一些包装和其他操作。这个过程不就是decorator所期望达到的效果吗?确实,在将函数作为参数这样传递的时候,我们无意间已经做到这个包装效果了。不过在python里,有一个更加典型的用法。我们还是以前面的示例为基础,假定我们已经定义好了outer方法和inner方法,我们将counter方法定义写成如下的方式:
>>> @outer ... def counter(): ... print("counter method execution")
然后我们再用这样的方式来执行counter方法:
>>> counter() Inner function before func execution. counter method execution
很奇怪,居然达到了一个同样的效果。实际上,我们的代码和前面的区别就在于加了一个@outer的修饰在方法定义上。问题的根源也就在于这里。这个@outer的修饰就相当于一个语法糖,我们执行counter()方法的时候实际上相当于变成了outer(counter)()。
我们来看基于函数的方式来定义的decorator。他们几乎有一个最外层的函数,这个函数相当于一个中介一样,它本身一般不做什么,通常只是用来返回内部的函数。当然,在一些特殊的情况下它可能会传递一些参数。然后内部的那个方法可以访问通过外部方法传递进来的参数,这些参数里通常就包含有需要包装的函数或者对象了。在这个内部方法里除了调用传进来的函数参数,我们也可以做一些自己定义的东西。这样,我们定义的函数式decorator就是这么回事了。
基于类的定义
看完前面基于函数的定义,我们再来看看基于类的定义。也许很多习惯了定义类的思路会更喜欢这种选择。不过确实,在实现上,基于类定义的方式显得更加直观和强大一些。我们先以前面的示例为基础,假设我们要定义一个outer的decorator类,那么我们该怎么做呢?
class outer(object): def __init__(self, func): self.func = func def __call__(self): print("Inner function before func execution.") return self.func()
这里我们将outer定义成一个类,然后我们需要传递的函数作为一个参数传递给__init__方法。然后原来inner方法里实现包装操作的方法我们放到__call__方法里。这样,我们按照原来的方式来使用这部分代码,执行结果如下:
>>> from outer import outer >>> @outer ... def counter(): ... print("counter method execution") ... >>> counter() Inner function before func execution. counter method execution
看了基于类方式定义decorator的方式。那么这种方式和基于函数定义的方式比起来,有什么好处呢?其实好处主要有这么些个。一个是这里将需要包装的函数作为参数传递进来,在传递过来时通过__init__方法来专门负责封装。而__call__方法来专门负责增加自定义的特性。这样两者的分离使得管理更加清晰。而且如果我们需要增加额外的属性也比较好管理。
和decorator pattern以及aop的关系
看了前面的示例,我们会发现python里的decorator其实可以做到好几个事。一个是decorator pattern。在我的这篇文章里讨论了decorator pattern。而decorator pattern我们知道,需要对一个对象的某些属性增加一些方法或者属性,所以我们要构造一个可以不断叠加属性进去的机制。而在decorator里,我们可以针对每个需要叠加的特性,定义好专门的decorator,然后再将需要被叠加的对象传递进来就可以了。和java的实现比起来显得更加简单直接。
decorator和java里的aop看起来也有很强的关系。在前面的示例里,我们可以在某个方法被调用前或者调用后执行某些代码。只要我们将这个decorator修饰加到目的对象上就可以了。如果在java里实现类似的功能呢?我们发现本身语言的支持还是比较困难的,比如说我们要实现一个annotation,然后还要用反射去处理。或者用专门的工具就为了操作byte code。所以说在java里比较困难的地方在python这里反而很简单了。
总结
Decorator在python里是一个基本的语言特性,使用它能够达到decorator pattern或者aop等效果。从更深的层次来说,它无非就是一个函数对另外一个函数对象的封装和传递。感觉和函数式编程语言里的curry化以及高阶函数有比较深的关系。后面有机会针对这两个点再深入的讨论讨论。
参考材料
http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
http://www.artima.com/weblogs/viewpost.jsp?thread=240808
https://wiki.python.org/moin/PythonDecoratorLibrary
http://www.jeffknupp.com/blog/2013/11/29/improve-your-python-decorators-explained/
http://stackoverflow.com/questions/20945366/python-decorators
相关推荐
在"python decorator==4.4.2"版本中,我们可以探讨这个库提供的装饰器功能及其在Odoo中的应用。 首先,让我们理解什么是Python装饰器。装饰器本质上是一个接收函数作为参数并返回新函数的函数。通过在定义函数前...
### Python Decorator 拦截器详解 在深入探讨Python中的`decorator`(装饰器)之前,我们先来了解一下什么是装饰器以及它为何被称为“拦截器”。 #### 一、装饰器简介 装饰器是一种特殊类型的函数,它可以修改...
2. **装饰器(Decorator)**: 装饰器是Python中实现装饰模式的一种方式。它是一个可调用的对象,通常是一个函数,接收一个函数作为参数,并返回一个新的函数。装饰器可以用来增强或修改原函数的功能,如日志、性能...
这个“python中完善decorator共5页.pdf.zip”文件很可能是关于深入理解和高效使用Python装饰器的教程,包含5页详细内容。以下是对Python装饰器及相关知识点的详细解释: 1. **装饰器的基本概念**:装饰器本质上是一...
Python中的装饰器(Decorator)是高级函数编程的一个重要特性,它允许我们修改或增强其他函数的功能,而无需改动原函数的代码。在Python中,装饰器本质上是一个接收函数作为参数并返回新函数的函数。本资料"python中...
Python中的装饰器是一种强大的工具,它允许我们修改或增强函数、类或其他可调用对象的行为,而无需修改它们的源代码。...理解并熟练掌握带参数装饰器的使用,对于提升Python编程技能和解决实际问题具有重要意义。
《Python库解析:json_log_decorator-2.0.0》 在编程领域,尤其是Python社区,库是开发者的重要工具,它们提供了预定义的功能,帮助我们更高效地编写代码。今天我们要探讨的是一个名为`json_log_decorator`的Python...
Python是一种广泛使用的高级编程语言,尤其在Web开发、数据分析、人工智能等领域有广泛应用。...在实际应用中,理解并熟练掌握如Potemkin Decorator这样的库,能够显著提升开发效率,同时保证代码的健壮性和可扩展性。
在Python编程语言中,装饰器(Decorator)模式是一种设计模式,它允许向现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,将原有的对象包裹在一个新的类中,并提供了与原类相同的接口。本文...
装饰器(Decorator)在Python编程语言中是一种强大的设计模式,它允许我们动态地修改或增强函数、类或对象的行为。...装饰器作为Python中的一个重要概念,对于理解和掌握高级Python编程技巧至关重要。
Python是一种高级编程语言,以其简洁明了的语法和丰富的标准库而受到广泛欢迎。"Python八股文"可能指的是对Python基础知识的一...以上是对Python中一些核心概念的详细解释,这些知识对于理解和使用Python编程至关重要。
在Python编程环境中,...在"python_资源"这个压缩包中,可能包含了与这些库相关的示例代码、教程或者额外的资源,可以帮助你更好地理解和应用这些库。解压并研究这些文件,将有助于提升你在图像和视频处理方面的技能。
第十二章“函数式编程”会讲解Python中的匿名函数(lambda)、高阶函数(如map、filter、reduce)以及装饰器(decorator),这些都是函数式编程的关键元素,能提升代码的简洁性和可读性。 第十三章“实战:原生爬虫”...
Python中的装饰器(decorator)是一种高级技巧,它们可以用来修改或增强函数的行为。 异常处理是任何编程语言中不可或缺的部分,Python 3使用try/except语句来捕获和处理异常。同时,Python 3引入了with语句,方便...
"Decorator-3.4.0" 是一个Python装饰器库的版本,提供了方便和灵活的方式来创建装饰器。这个版本的压缩包文件名为"decorator-3.4.0.tar.gz",它是一个常见的归档格式,用于存储和分发源代码。 在Python中,装饰器...
这个“超级无敌Python教程”强调实践,让你通过实例学习,以加深对Python的理解。 首先,Python的基础知识包括变量、数据类型和操作符。变量是存储信息的容器,你可以将其想象为一个可以改变其值的标签。Python支持...
这份文档提供了全面的指南、教程和参考材料,帮助开发者深入理解Python的特性和用法。 首先,Python 3.8.2引入了一些重要的语法更新和改进。例如,赋值表达式(walrus operator :=)允许在条件语句中同时检查和赋值...
在学习Python的过程中,理解并掌握其语法是至关重要的,因为它是后续深入学习和应用的基础。 **Python基础教程内容概览** 1. **第一个Python程序和数据存储**:这部分将介绍如何编写和运行Python的第一个程序,...
Python装饰器是一种高级编程技巧,它...通过这个项目,你可以深入理解装饰器的工作原理,以及如何在实际项目中应用它们。实践中,装饰器可用于日志记录、性能测试、权限控制等多种场景,是Python开发中的一个重要工具。