|
继续闭包话题,留点心得体会。
前博文写了点关于闭包的理解,举了个直线函数的例子,可能你会说,可以设计line函数时,传3个参数不就可以了吗,即def line(x,a,b),这确实是可以实现类似的功能,说明下,举这个例子仅用来说明闭包,今天接着写点闭包的用法,装饰器就是经典的用法,甚至有人说,不懂装饰器,不能说自己懂python,哈哈
还有一个问题,上篇忘记说的,闭包有个缺点就是函数执行完,不能释放闭包中的变量,拿上篇的闭包来说明下:
# 传入参数a=10,b=20,下面代码line01将指向函数line(line_conf函数内定义的那个函数),同时变量a=10,b=20,一起形成一个闭包
line01=line_conf(10,20)
# 下面执行line01,传入一个x值100,将返回10*100+20
line01(100)
要说明的是,一般函数执行完成,局部变量立刻从内存中释放,但闭包不同,这里闭包含函数line、变量a和b,执行line01时调用line函数执行,执行时调用闭包中的变量a和b(10和20),执行完成后,变量a和b将不能被释放,这是闭包的缺点,不能释放内存。
回归主题,装饰器是什么?看下面代码,这就是一个装饰器,函数名w1、inner可自己随意,合法就行。
def w1(func):
# 定义一个函数,参数为引用函数,变量名func随意,这里意思是个函数
def inner(): #
定义一个内部函数
… # 功能代码
func() # 执行引用函数
return inner # 返回内部函数
看结构是不是象闭包的写法,如果仔细看,你会发现不同之处在于,外面的函数传入的参数是一个函数,并且在内部函数中,执行了传入的函数!
这有什么用?举个简单例子:
# 定义一个函数say_hello,就一个功能,执行就打印一个字符串hello
def say_hello():
print(“hello”)
现在我要实现不修改原函数的情况下,添加一个功能,再输出打印一个字符串byebye,看我用装饰器来做,就用上面那个装饰器,参考代码:
def w1(func):
def inner():
func()
print(“byebye”) # 新增加的功能代码
return inner
# 下面代码,执行装饰器函数w1,将函数say_hello作为参数传入,返回给变量new_sayhello
new_sayhello = w1(say_hello)
# 下面代码,执行new_sayhello,将看到输出hello、byebye
new_sayhello()
上面的代码可以在不修改原函数代码的情况下,给函数增加功能,具体怎么实现的,小结下:
执行w1(say_hello),new_sayhello应该得到一个返回的inner,inner就是装饰器内的一个函数,注意new_sayhello这时仅指向这个函数定义,并没有执行,还有,根据闭包的说法,new_sayhello指向的函数inner,和外部函数w1传入的参数func一起构成一个闭包,对不对,如果没想明白,看看上篇闭包。
继续看下来,如果理解了闭包,就能理解下面这些(也许每个人的表述带偏见,看不明白的话可与我交流,这里主要是写给自己做个小结):
new_sayhello = w1(say_hello)
这步执行后,new_sayhello指向了一个函数inner,附带一个参数func,一起构成一个闭包。
func是传入的函数,这里传入的是say_hello函数
inner函数又是什么?其实就是func,也就是传入的函数say_hello,再加新功能代码,假如执行inner函数,其实就是执行say_hello(),再执行新功能代码print(“byebye”)
上段总结一句话,经过装饰器后,new_sayhello就是一个指向inner函数的函数,执行new_sayhello就相当执行inner函数,而执行inner函数,就等于执行say_hello,再加执行新添加的代码(新加代码可以添加到func()前面和后面)
感觉说得有点啰嗦,个人小结为主,欢迎交流。
继续:装饰器在python中使用有一个固定语法,如装饰器(就上面那个吧)
def w1(func):
def inner():
func()
print(“byebye”) # 新增加的功能代码
return inner
装饰器装饰函数的写法:
@w1
def fn():
函数代码
这样写,解释器读到这里时,相当执行fn=w1(fn)
这里fn与原函数名fn相同,但执行完成后fn就不是原来的fn了,而是改造后的fn
再啰嗦几句,按上面的装饰器理解,fn指向w1内的inner函数,而inner函数由原函数fn和新功能代码组成,哈哈!
而且一个装饰器可以装饰多个函数,只要在函数定义前@xxx,即可,如
@w1
def fn1():
…
@w1
def fn2():
…
关于装饰器,还有一些用法,如一个函数可以用多个装饰器装饰,还有关于传参,即被装饰的函数如果有传参,还有关于被装饰的函数本身有返回值的情况,这篇有点太长,先不总结了。 |