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实例
那么剩下的就是很简单的方法调用了。