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实例

那么剩下的就是很简单的方法调用了。

 

posted @ 2014-08-27 17:32  棉花年度  阅读(220)  评论(0编辑  收藏  举报