闭包
➢如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,则该函数称为闭包。
闭包是Python所支持的一种特性,它让在非global scope定义的函数可以引用其外围空间中的变量,这些外围空间中被引用的变量叫做这个函数的环境变量。环境变量和这个非全局函数一起构成了闭包。
闭包-------返回一个函数以及执行这个函数所需要的相关变量。一般用在嵌套函数中。
#coding=utf-8
def outer() :
name = "python"
def inner() :
print (name)
return inner
res = outer()
res()
print (res. __closure__)
#coding=utf-8
def outer(name) :
def inner() :
print (name)
return inner
res1 = outer("python")
print (res1. __closure__)
res2 = outer("java")
res1()
res2()
装饰器-------给函数增加一些通用的功能
比如给所有的函数都计算一下执行的时间。
装饰器其实就是一个闭包,把一个函数当做参数后返回一个替代版函数。
在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式,称之为装饰器(Decorator)。
装饰器是一个很著名的设计模式,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
总体来说,装饰器其实也是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值给原来的标识符,并永久丧失对原始函数对象的访问。
1、函数调用基础知识复习:
>>> def func():
... print("hi")
... return 10
...
>>> func()
hi
10
>>> a=func()
hi
>>> a
10
>>> a=func #把函数对象赋给a
>>> a
<function func at 0x002B5B70>
>>> a() #调用函数
hi
10
2、装饰器的实现原理
def deco(func):
def _deco():
print ("before myfunc() called.")
func()
func()
print (" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
def myfunc(): #等价于闭包:_deco()+myfunc
print (" myfunc() called.")
return 'ok'
myfunc=deco(myfunc)
myfunc() #等价于闭包:_deco()+myfunc
3、最简单的装饰器实现
def deco(func):
def _deco():
print ("before myfunc() called.")
func()
print (" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
#@deco等价于myfunc = deco(myfunc)
@deco
def myfunc():
print (" myfunc() called.")
return 'ok'
myfunc()
myfunc()
装饰器的好处:能够给所有的函数增加一些附加的功能。
本质就是:@deco是个装饰函数,他需要返回一个闭包。闭包有_deco函数对象+原函数对象(闭包变量)。
_deco函数对象本质:执行了附加的功能,并且执行了原函数。
小练习:利用装饰器给函数执行计算下耗时
import time
def deco(func):
def _deco():
print ("before myfunc() called.")
time1=time.time()
func()
time.sleep(2)
time2=time.time()
print (" after myfunc() called.")
print("%s函数执行耗时:%s" %(func.__name__,time2-time1))
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc(): #等价于闭包:_deco()+myfunc
print (" myfunc() called.")
return 'ok'
myfunc() #等价于闭包:_deco()+myfunc
myfunc和myfunc()执行的结果区分:
#coding=utf-8
def deco(func):
print("hi")
def _deco():
print ("before myfunc() called.")
func()
print (" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc(): #等价于闭包:_deco()+myfunc
print (" myfunc() called:")
#myfunc #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
myfunc() #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
#加了括号后--->_deco()被执行了
4、对带参数的函数进行装饰:
import time
def deco(func):
def _deco(a,b):
print ("before myfunc() called.")
time1=time.time()
func(a,b)
time.sleep(2)
time2=time.time()
print (" after myfunc() called.")
print("%s函数执行耗时:%s" %(func.__name__,time2-time1))
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc(a,b): #等价于闭包:_deco(a,b)+myfunc
print (" myfunc() called:",a,b)
return 'ok'
myfunc(1,2) #等价于闭包:_deco(1,2)+myfunc
5、对参数数量不确定的函数进行装饰----兼容可变参数:
#coding=utf-8
def deco(func):
print("hi")
def _deco(*arg,**kw):
print ("before myfunc() called.")
func(*arg,**kw)
print (" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc(a,b): #等价于闭包:_deco(a,b)+myfunc
print (" myfunc() called:",a,b)
@deco
def myfunc1(a,b,c,d,*agg,**kw): #等价于闭包:_deco(a,b,c,d,*agg,**kw)+myfunc
print (" myfunc() called:",a,b,c,d)
print(kw)
#myfunc #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
myfunc(1,2) #--->deco(myfunc)--->执行结果:返回闭包_deco+myfunc
#加了括号后--->_deco()被执行了
myfunc1(1,2,3,4,e=10)
6、让装饰器带参数,多了一层闭包
#coding=utf-8
def deco(arg):
print("1")
def _deco(func):
print("2")
def __deco():
print("3")
print ("before %s called [%s]." % (func.__name__, arg))
func()
print (" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("mymodule") #等价于deco("mymodule")--->一级闭包_deco+arg
#二级闭包_deco(myfunc)+arg
#myfunc()--->_deco()
def myfunc():
print (" myfunc() called.")
#myfunc #执行1和2,没有执行3--->返回闭包_deco+arg+myfunc
myfunc() #执行1和2,3--->_deco()