本篇依然是一篇学习笔记,文章的结构首先讲装饰器,然后讲lambda表达式。装饰器内容较多,先简要介绍了装饰器语法,之后详细介绍理解和使用不带参数装饰器时应当注意到的一些细节,然后实现了一个简单的缓存装饰器作为实践,最后在理解不带参数的装饰器的基础上,介绍了理解和使用带参数的装饰器需要注意到的细节。lambda表达式的讲解依然着重于使用细节和理解上。如果有不对的地方欢迎指正。
装饰器
实际上理解装饰器的作用很简单,在看core python相关章节的时候大概就是这种感觉。只是在实际应用的时候,发现自己很难靠直觉决定如何使用装饰器,特别是带参数的装饰器,于是摊开来思考了一番,写下一些心得。
装饰器简述
为了完整起见,这里简要说明一下装饰器的语法。装饰器分为带参数得装饰器以及不带参数得装饰器。装饰器以及使用效果看起来大概是这样的。
#语法是这个样子的
@decorator(dec_opt_args)
def func2Bdecorated(func_opt_args):
...
#不带参数的装饰器
@dec1
@dec2
def func():
...
#这个函数声明等价于
func = dec1(dec2(func))
#带参数的装饰器
@dec(some_args)
def func():
...
#这个函数声明等价于
func = dec(some_args)(func)
不带参数的装饰器需要注意的一些细节
这里将说明使用带参数的装饰器时需要注意的一些细节。并会实现一个简单缓存装饰器,来帮助理解。
1. 关于装饰器函数(decorator)本身
对于被装饰的函数func,不带参数的装饰器接受一个函数为参数,并返回一个装饰过的函数decorated_func。因为对返回的函数没有限制,所以decorator函数甚至可以返回与func完全无关的新函数。但是大部分情况下,decorated_func是对func的额外处理,因此一个装饰器一般对应两个函数,一个是decorator函数,用来进行一些初始化操作处理,一个是decorated_func用来实现对被装饰的函数func的额外处理。并且为了保持对func的引用,decorated_func一般作为decorator的内部函数,比如:
#一般将decorated_func作为decorator的内部函数
#因为内部函数可以保持对func的引用(详见(1)的闭包讲解)
>>> def decorator(func):
... print 'init opration'
... def decorated_func():
... return func(2)
... return decorated_func
...
2. decorator函数只在函数声明的时候被调用一次
装饰器实际上是语法糖,在声明函数之后就会被调用,产生decorated_func,并把func符号的引用替换为decorated_func。之后每次调用func函数,实际调用的是decorated_func。
>>> def decorator(func):
... def decorated_func():
... func(1)
... return decorated_func
...
#声明时就被调用
>>> @decorator
... def func(x):
... print x
...
decorator being called
#使用func()函数实际上使用的是decorated_func函数
>>> func()
1
>>> func.__name__
'decorated_func'
如果要保证返回的decorated_func的函数名与func的函数名相同,应当在decorator函数返回decorated_func之前,加入decorated_func.name = func.name, 另外functools模块提供了wraps装饰器,可以完成这一动作。