Python闭包及装饰器
Python闭包
先看一个例子:
def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6)
我们定义了一个方法outer,方法内部又定义了一个方法inner,方法outer返回值为内部定义的方法inner。
同时,内部方法innder使用了外部方法的参数x。
从我们的调用方式可以清晰地看到,add=outer(8)相当于add接受了类似于下边一个方法
def inner(y): return 8+y
然后调用add(6),结果显示14
这其实就是一个简单的闭包。
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
下边是另一个闭包的实例--方法作为参数传递
def tsfunc(func,x): def wrappedFunc(): print func.__name__ return func(x) return wrappedFunc() def foo(x): print 'aaa' + x if __name__=='__main__': tsfunc(foo , "x")
结果是:
foo
aaax
我们把方法foo当做参数传递到另一个方法tsfunc内,然后在tsfunc内做了其他一些事情(这里我们只是打印了foo的name),最后又返回来foo,并使用了额外参数。
装饰器
不带参数的装饰器
和上边一样,举个例子,如下:
def decorator(F): def new_F(a, b): print "input", a, b return F(a, b) return new_F @decorator def sub(a,b): return a-b def add(a,b): return a+b print sub(3,4) add = decorator(add) print add(3, 4)
结果如下:
input 3 4
-1
input 3 4
7
对比sub的调用和add的调用,其实他们是完全一样的运行方式,只不过装饰器将语法包裹起来,看起来更干净一些。
或许你现在发现一个问题,如果我们要给装饰器加参数,在被装饰的方法内部使用该怎么做呢?
装饰器工厂(带参数的装饰器)
在装饰器基础上再增加一层嵌套,其定义和实现装饰器是一样的,看下边的例子:
# a new wrapper layer def pre_str(pre=''): # old decorator def decorator(F): def new_F(a, b): print(pre + "input", a, b) return F(a, b) return new_F return decorator @pre_str('^_^') def sub(a,b): return a-b def add(a,b): return a+b print sub(3,4) dec = pre_str('&_&') add = dec(add) print add(3, 4)
这个也是很好理解的了吧,我们的装饰运行方式和分步调用是同一个效果的。
这样就实现了装饰器语法传递参数,效果还不错。
类装饰器
看下边例子:
def decorator(aClass): class newClass: def __init__(self, age): self.total_display = 0 self.wrapped = aClass(age) def display(self): self.total_display += 1 print "total display:%s" % self.total_display self.wrapped.display() return newClass @decorator class Bird: def __init__(self, age): self.age = age def display(self): print "My age is %s"% self.age eagleLord = Bird(5) for i in range(3): eagleLord.display()
运行结果:
定义了decorator作用给类Bird,当初始化Bird类时,装饰器会先进行初始化,使用Bird初始化的参数,然后返回一个装饰器内定义的类。
例子中装饰器内的类包裹了一个Bird类实例,并实例化。根据单步调试来看,Bird类初始化只进行了一次,即相当于Bird的初始化时在装饰器内被调用生成实例时调用的。
要注意的是:Bird(5)的返回值并不是Bird实例,而是装饰器内的类newClass实例
那么剩下的就是很简单的方法调用了。