一、闭包:
闭包就是内层函数引用了外部函数的变量,然后返回内层函数的情况。闭包的特点就是我们返回的函数,引用了外部函数的局部变量,如果我们希望按照我们所想,来正确的使用这个闭包的话,那就要确定我们引用的局部变量在函数返回以后不能更改。
一个最简单的闭包:
def outer(arg):
def inner():
return 'Using args:' + arg
return inner
f = outer('hello')
print f()
例如上面的例子,我们定义了一个outer()函数,同时在里面定义了一个inner()函数。inner()函数使用了outer()中的参数arg,然后我们返回inner函数。所以总的来说,outer函数的返回值是内部定义的inner,同时inner使用了outer()中的参数。
那么什么叫外部的参数不能改变呢?
比如,我们定义一个函数getFunc(),这个函数返回了三个函数,分别定义1+1,2+2,3+3
def getFaunc():
L = []
for i in range(1,4):
def f():
return i+i
L.append(f)
return L
f1,f2,f3 = getFaunc()
print f1(),f2(),f3()
结果发现,最后的结果均是3+3。因为在我们添加完第三个函数的时候,i=3,内部函数使用到的外部参数改变了,所以我们的闭包没有正确运行
更改为如下所示:
def getFaunc():
L = []
for i in range(1,4):
def f(i):
def g():
return i+i
return g
tmp = f(i)
L.append(tmp)
return L
f1,f2,f3 = getFaunc()
print f1(),f2(),f3()
区别就是,在第二段代码中,我们执行了f(i)函数,这就使得相对的g中的变量i固定为当前f执行时的i,从而不会导致外部的变量改变这种情况
二、Python装饰器
Python装饰器,顾名思义就是给函数起到装饰功能,这就意味着:首先是仅是装饰而不会更改函数的任何代码,第二个就是就是增加原有函数的功能。
举个例子,我们有一个函数是打印当天的日期:
import time
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
print getDate()
如果我们希望在打印日期的时候,在服务器上打印当前的时间,而又不希望更改代码。这时候就可以使用装饰器
import time
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
def getDateAndTime(f): # 装饰器函数,将原函数作为参数传入装饰器函数
def newGetDate(): #在内部声明一个新函数
print '[SERVER] Current time: '+time.strftime('%H-%M-%S',time.localtime(time.time())) #增加的新功能
return f() # 返回原函数执行
return newGetDate #返回新函数
getDate = getDateAndTime(getDate) #屏蔽掉原有函数
print getDate()
装饰器看上去很复杂,自底向上拆成以下步骤很好理解:
1. 首先,要屏蔽掉原有函数,将原有函数传入装饰器函数,获得新函数,所以我们需要构造装饰器函数
2. 在定义的装饰器函数内部,我们需要定义一个新的函数,扩展功能,并作为装饰器函数的返回值
3. 在新函数的内部,扩展新的函数。同时将原函数执行,并作为 返回值返回。
在python中使用这种方法来实现切面。同时,python提供了@这样的语法糖,让我们可很好的使用装饰器,而不用每次都是使用getDate = getDateAndTime(getDate),来屏蔽原有函数
import time
def getDateAndTime(f):
def newGetDate():
print '[SERVER] Current time: '+time.strftime('%H-%M-%S',time.localtime(time.time()))
return f()
return newGetDate
@getDateAndTime
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
print getDate()
与之前相比,我们只需要将@+装饰器函数标注在原有函数上,就实现屏蔽原函数的作用。除此之外,python装饰器也可以带上参数
import time
def log(arg):
def getDateAndTime(f):
def newGetDate():
print '['+arg+']' +'Current time: '+time.strftime('%H-%M-%S',time.localtime(time.time()))
return f()
return newGetDate
return getDateAndTime
@log('SERVER')
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
print getDate()
在原有的基础上,多套了一层函数来接收参数。
上面代码可以解释为:
getDateAndTime = log('SERVER')
getDate = getDateAndTime(getDate)
P.S. 文章不妥之处还望指正