闭包的构成条件:
在函数嵌套(函数里面再定义函数)的前提下
内部函数使用了外部函数的变量(还包括外部函数的参数)
外部函数返回了内部函数
简单来说就是:有嵌套,有引用,有返回。
然后最近在敲代码的过程中发现:被装饰的函数和闭包中的内部函数都是一样的参数。
简单闭包
闭包其实是为了装饰器服务的,闭包其实本身没什么用。
关键点在于创建闭包实例,比如$f = fun_out(1)$其实$f$不是普通变量,而是一个函数对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 def fun_out (num1 ): def fun_inner (num2 ): result = num2 + num1 print ("结果是: " , result) return fun_inner f = fun_out(1 ) f(2 ) f(3 )
当返回的内部函数使用了外部函数的变量就形成了闭包
闭包可以对外部函数的变量进行保存
闭包的作用 闭包的作用: 闭包不仅可以保存外部函数的变量还可以提高代码的可重用性(不需要再手动定义额外的功能函数
1 2 3 4 5 6 7 8 9 10 11 12 13 def config_name (name ): def say_info (info ): print (name + ":" + info) return say_info tom = config_name("Tom" ) tom("你好!" ) tom("你好,在吗?" ) jerry = config_name("jerry" ) jerry("不在,不和你玩!" )
闭包-nolocal关键字
类似于在局部范围内(函数内)修改全局变量的一个性质。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def fn_outer (): a = 100 def fn_inner (): nonlocal a a += 1 print (a) return fn_inner if __name__ == '__main__' : fn_inner = fn_outer() fn_inner() fn_inner() fn_inner()
装饰器的功能特点:
如下的函数是演示装饰器的第一种写法。也就是偷偷摸摸给函数添加了一个需要登录的功能,函数名称不变。
不修改已有函数的源代码
不修改已有函数的调用方式
给已有函数增加额外的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def check (fn ): def inner (): print ("请先登陆!" ) fn() return inner def comment (): print ("发表评论!" ) comment = check(comment) comment()
闭包函数有且只有一个参数,必须是函数类型,这样定义的函数才是装饰器。
写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。
装饰器的语法糖写法
如果有多个函数都需要添加登录验证的功能,每次都需要编写func = check(func)这样代码对已有函数进行装饰,这种做法还是比较麻烦。
Python给提供了一个装饰函数更加简单的写法,那就是语法糖,语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰
糖写法演示 1 2 3 @check def comment (): print ("发表评论" )
@check ==> comment = check(comment)
使用装饰器添加登陆验证功能 1 2 3 4 5 6 7 8 9 10 11 12 def check (fn ): print ("装饰函数执行了" ) def inner (): print ("请登陆...." ) fn() return inner @check def comment (): print ("发表评论!" ) comment()
使用装饰器对函数执行时间进行统计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import timedef get_time (func ): def inner (): begin_time = time.time() func() end_tiem = time.time() print ("函数执行花费了:%f" % (end_tiem-begin_time)) print ("测试:" ,end_tiem-begin_time) return inner @get_time def test (): for i in range (10000000 ): i += 1 print (i) test()
带有不定长参数的装饰器 *args和**kwargs都是可变长度参数的方式
*args:用于传递不定数量的位置参数,它会将所有的位置参数打包成一个元组(tuple)。
**kwargs:用于传递不定数量的关键字参数,它会将所有的关键字参数打包成一个字典(dictionary)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def logging (fun ): def inner (*args, **kwargs ): print ("--正在努力计算--" ) fun(*args, **kwargs) return inner @logging def sum_num (*args, **kwargs ): result = 0 for vaules in args: result += vaules for vaules in kwargs.values(): result += vaules print (result) sum_num(1 , 2 , a=10 )
通用装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 def logging (fn ): def inner (*args, **kwargs ): print ("--正在努力计算--" ) result = fn(*args, **kwargs) return result return inner @logging def sum_num (*args, **kwargs ): result = 0 for value in args: result += value for value in kwargs.values(): result += value return result @logging def subtraction (a, b ): result = a - b print (result) result = sum_num(1 , 2 , a=10 ) print (result)subtraction(4 , 2 )