Python里的闭包和AOP

来源:互联网 发布:java框架整合 编辑:程序博客网 时间:2024/05/29 10:19

习惯了写Java和JS代码,突然换成Python还真不习惯,最近在书上看到一段挺有意思的Python代码,才真心感觉到Python长盛不衰的价值。在很多语言里,如果在一个内部函数里,对外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。定义在外部函数内的但由内部函数引用或者使用的变量被称为自由变量。闭包的词法变量不属于全局或者局部作用域,而属于一种“流量”的作用域。


先介绍一种语法,Python有种叫函数装饰器的东西,这是一种特殊的函数,因为它接受函数对象为参数,对其进行封装加工并返回。举个简单的例子:

@deco(deco_args)def foo(): pass#相当于:foo = deco(deco_args) (foo)

装饰器封装了foo,并返回新版本的foo。这其实就是一种闭包的用法,因为无论在deco函数中定义了那些变量,当调用新版本foo的时候都可以访问到它们,那些变量并不随着deco函数的执行结束返回而销毁,而是继续存活在“流量”空间里等待被激活。如果要问这有什么作用?最容易理解的就是对比Java里的AOP概念,在不改变源代码的情况下,织入切面,添加统一的逻辑:打日志、性能指标记录、统一事务管理等等。而在python里面,AOP居然如此之简单,通过函数装饰器和闭包的特性就可以轻易解决。下面这个例子,就是对闭包强大特性的一个体现:(给方法hello添加执行时间的分析,不改动原方法hello的代码)

#!usr/bin/env pythonfrom time import timedef logged(when):def log(f, *args, **kargs):print '''Called:function: %sargs: %rkargs: %r''' % (f,args,kargs)def pre_logged(f):def wrapper(*args, **kargs):log(f, *args, **kargs)return f(*args, **kargs)return wrapperdef post_logged(f):def wrapper(*args, **kargs):now = time()try:return f(*args, **kargs)finally:log(f, *args, **kargs)print "time delta: %s" % (time()-now)return wrappertry:return {"pre": pre_logged, "post": post_logged}[when]except:raise ValueError(e), 'must be "pre" or "post"'@logged("post")def hello(name):print "Hello, ", namehello("World")

可以看到只是简单的在hello方法前添加了一个函数装饰器,就可以让hello的调用具有分析执行时间的特性,成功的织入切面!我这的执行结果是:

Hello,  WorldCalled:function: <function hello at 0x10755aa28>args: ('World',)kargs: {}time delta: 3.88622283936e-05




原创粉丝点击