闭包的介绍
闭包的定义:
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
闭包的构成条件
通过闭包的定义,我们可以得知闭包的形成条件:
- 在函数嵌套(函数里面再定义函数)的前提下
- 内部函数使用了外部函数的变量(还包括外部函数的参数)
- 外部函数返回了内部函数
简单闭包的示例代码
# 定义一个外部函数 def func_out(num1): 定义一个内部函数 func_inner(num2): 内部函数使用了外部函数的变量(num1) result = num1 + num2 print("结果是:",result) 外部函数返回了内部函数,这里返回的内部函数就是闭包 return func_inner 创建闭包实例 f = func_out(1) 执行闭包 f(2) f(3)
运行结果:
结果是: 3
结果是: 4
闭包执行结果的说明:
通过上面的输出结果可以看出闭包保存了外部函数内的变量num1,每次执行闭包都是在num1 = 1 基础上进行计算。
闭包的作用
- 闭包可以保存外部函数内的变量,不会随着外部函数调用完而销毁。
注意点:
- 由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。
小结
- 当返回的内部函数使用了外部函数的变量就形成了闭包
- 闭包可以对外部函数的变量进行保存
-
实现闭包的标准格式:
外部函数 test1(a): b = 10 内部函数 test2(): 内部函数使用了外部函数的变量或者参数 print(a,b) 返回内部函数,这里返回的内部函数就是闭包实例 return test2
闭包的使用
需求: 根据配置信息使用闭包实现不同人的对话信息,例如对话:
张三: 到北京了吗?
李四: 已经到了,放心吧。
外部函数 config_name(name): 内部函数 say_info(info): print(name + : " + info) say_info tom = config_name(Tom) tom(你好!) tom(你好,在吗?) jerry = config_name(jerry) jerry(不在,不和你玩!")
运行结果:
Tom: 你好!
Tom: 你好,在吗?
jerry: 不在,不和你玩!
修改闭包内使用的外部变量
func_out(num1): 这里本意想要修改外部num1的值,实际上是在内部函数定义了一个局部变量num1 num1 = 10 (num1) func_inner(1) (num1) 创建闭包实例 f = func_out(1 执行闭包 f(2)
修改闭包内使用的外部变量的正确示例:
这里本意想要修改外部num1的值,实际上是在内部函数定义了一个局部变量num1 nonlocal num1 告诉解释器,此处使用的是 外部变量a 修改外部变量num1 num1 = 10 执行闭包 f(2)
装饰器的定义
就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数。
装饰器的功能特点:
- 不修改已有函数的源代码
- 不修改已有函数的调用方式
- 给已有函数增加额外的功能
装饰器的示例代码
添加一个登录验证的功能 check(fn): inner(): 请先登录....) fn() inner comment(): 发表评论) 使用装饰器来装饰函数 comment = check(comment) comment()
代码说明:
- 闭包函数有且只有一个参数,必须是函数类型,这样定义的函数才是装饰器。
- 写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。
执行结果:
请先登录....
发表评论
装饰器的语法糖写法
如果有多个函数都需要添加登录验证的功能,每次都需要编写func = check(func)这样代码对已有函数进行装饰,这种做法还是比较麻烦。
Python给提供了一个装饰函数更加简单的写法,那就是语法糖,语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰
装饰器函数执行了 inner 使用语法糖方式来装饰函数 @check ) comment()
说明:
- @check 等价于 comment = check(comment)
- 装饰器的执行时间是加载模块时立即执行。
执行结果:
请先登录....
发表评论
装饰器的使用
- 函数执行时间的统计
- 输出日志信息
装饰器实现已有函数执行时间的统计
import time 装饰器函数 get_time(func): inner(): begin = time.time() func() end = time.time() 函数执行花费%f" % (end-begin)) inner @get_time func1(): for i in range(100000): (i) func1()
执行结果:
... 99995 99996 99997 99998 99999 函数执行花费0.329066
装饰带有参数的函数
添加输出日志的功能 logging(fn): inner(num1,num2): --正在努力计算--) fn(num1,num2) 使用装饰器装饰函数 @logging sum_num(a,b): result = a + b (result) sum_num(1,2)
运行结果:
--正在努力计算-- 3
装饰带有返回值的函数
) result = fn(num1,num2) result result result = sum_num(1,2print(result)
运行结果:
--正在努力计算-- 3
装饰带有不定长参数的函数
def inner(*args,**kwargs): ) fn(*args,1)">kwargs) 使用语法糖装饰函数 def sum_num(*args,1)">kwargs): result = 0 for value in args: result += value kwargs.values(): result +=(result) sum_num(1,2,a=10)
运行结果:
--正在努力计算-- 13
通用装饰器
) result = fn(*args,1)">kwargs) result result @logging subtraction(a,b): result = a -(result) result = sum_num(1,a=10(result) subtraction(4,2)
运行结果:
--正在努力计算-- 13 --正在努力计算-- 2
多个装饰器的使用示例代码
make_div(func): """对被装饰的函数的返回值 div标签""" return <div>" + func() + </div>" make_p(func): 对被装饰的函数的返回值 p标签<p></p> 装饰过程: 1 content = make_p(content) 2 content = make_div(content) # content = make_div(make_p(content)) @make_div @make_p content(): 人生苦短 result = content() print(result)
带有参数的装饰器介绍
错误写法:
decorator(fn,flag): if flag == +: --正在努力加法计算--) elif flag == ---正在努力减法计算-- inner @decorator('' add(a,1)"> result result = add(1,3print(result)
正确写法:
在装饰器外面再包裹上一个函数,让最外面的函数接收参数,返回的是装饰器,因为@符号后面必须是装饰器实例。
logging(flag): decorator(fn): : ) ) result = result inner 返回装饰器 decorator 使用装饰器装饰函数 @logging( result @logging( sub(a,1)">(result) result = sub(1,1)">print(result)
装饰器的执行顺序
time
def log(level="info"):
print ("log")
decorater(func): print (wrapper start) def wrapper(*args,1)">kwargs): print( inner_wrapper start) func(*args,1)">kwargs) inner_wrapper endwrapper endreturn wrapper
print ("end")
return decorater
原文地址:https://www.cnblogs.com/tracydzf
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。