第一章 闭包和装饰器
1.1 闭包
闭包的定义
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
闭包的构成条件
通过闭包的定义,我们可以得知闭包的形成条件:
1.在函数嵌套(函数里面再定义函数)的前提下
2.内部函数使用了外部函数的变量(还包括外部函数的参数)
3.外部函数返回了内部函数
#闭包的作用:可以保存外部函数的变量
#闭包的形成条件
# 1.函数嵌套
#2. 内部函数使用了外部函数的变量或者参数
# 3.外部函数返回内部函数,这个使用了外部函数变量的内部函数称为闭包
# 1.函数嵌套
def func_out():
#外部函数
num1 = 10
def func_inner(num2):
#内部函数
#2.内部函数使用了外部函数的变量
result = num1 + num2
print("结果:",result)
#外部函数要返回内部函数,这个使用了外部函数变量的内部函数称为闭包
return func_inner
# 获取闭包对象
new_func=func_out()
# 执行闭包
new_func(2)
1.2 闭包的使用
案例
需求:根据配置信息使用闭包实现不同人的对话信息,例如对话:张三:到北京了吗?李四:已经到了,放心吧。
实现步骤说明
1.定义外部函数接收不同的配置信息参数,参数是人名
2.定义内部函数接收对话信息参数
3.在内部函数里面把配置信息和对话信息进行拼接输出
#外部函数接收姓名参数
def config_name (name) :
#内部函数保存外部函数的参数,并且完成数据显示的组成
def inner(msg) :
print(name + ":" + msg)
print(id(inner))
#外部函数要返回内部函数
return inner
#创建tom闭包实例(对象)
tom = config_name ("tom" )
#创建jerry闭包实例
jerry = config_name("jerry")
#如果执行tom闭包,因为已经保存了name参数,那么以后在输入的时候都是, tom说:xxx
tom("哥们,过来一下,我们一起玩要! ")
jerry("好")
1.3 修改闭包内使用的外部变量
def func_out():
num1=10
def func_inner():
# 在闭包内修改外部函数的变量需要使用nonlocal关键字
nonlocal num1
num1=20
result=num1+10
print(result)
print("修改前的变量",num1)
func_inner()
print("修改后的变量",num1)
func_out()
1.4 装饰器
装饰器的定义
就是给已有函数增加额外功能的函数,它本质上就是- -个闭包函数。
装饰器的功能特点
1.不修改已有函数的源代码
2.不修改已有函数的调用方式
3.给已有函数增加额外的功能
装饰器的语法糖写法
如果有多个函数都需要添加登录验证的功能,每次都需要编写func = check(func)这样代码对已有函数进行装饰,这种做法还是比较麻烦,Python给提供了一个装饰函数更加简单的写法,那就是语法糖,语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰,装饰器会在模块加载完成时立即执行
#学习装饰器目的:对已有函数进行额外的功能扩展,装饰器本质上是一个闭包函数,也就是说他也是一个函数嵌套
#装饰器的特点:
# 1.不修改已有函数的源代码
# 2.不修改已有函数的调用方式
# 3.给以后函数添加额外的功能
# 装饰器
def decorator(func):
print("装饰器执行了")
def inner():
print("以添加登陆验证")
func()
return inner
@decorator
def commnet():
print("发表评论")
# 调用装饰器对已有函数进行装饰
# commnet=decorator(commnet)
commnet()
1.5 装饰器的使用
1.装饰器的使用场景
1.函数执行时间的统计
2.输出日志信息
import time
#装饰器函数
def get_time(func):
def inner():
begin = time.time()
func()
end = time.time()
print("函数执行花费%f" % (end-begin))
return inner
@get_time
def work():
for i in range(10000):
print(i)
work()
1.6 通用装饰器的使用
装饰带有参数的函数
# 通用的装饰器
def decorator(func):
def inner(*args,**kwargs):
print("正在执行加法计算")
# *args: 把元组里面的每一个元素,按照位置参数的方式进行传参
# **kwargs: 把字典里面的每一个键值对,按照关键字的方式进行传参
# 这里对元组和字典进行拆包,仅限于结合不定长参数的函数使用
num=func(*args,**kwargs)
return num
return inner
@decorator
def add_num(num1,num2,num3):
result=num1+num2+num3
print("结果为:",result)
return result
result1=add_num(num1=1,num3=2,num2=6)
print(result1)
result2=add_num(1,2,3)
print(result2)
1.7 多个装饰器的使用
#定义装饰器
def make_div(func):
print("make_div装饰器执行了")
def inner():
result="<div>"+func()+"</div>"
return result
return inner
def make_p(func):
print("make_p装饰器执行了")
def inner():
result="<p>"+func()+"</p>"
return result
return inner
# 多个装饰器的过程: 由内到外的一个装饰过程,先执行内部的装饰器,在执行外部的装饰器
# content=make_div(make_p(content))
@make_div
@make_p
def content():
return "人生苦短,我用python"
result=content()
print(result)
'''
make_p装饰器执行了
make_div装饰器执行了
<div><p>人生苦短,我用python</p></div>
'''
1.8 带有参数的装饰器
带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数,语法格式:@装饰器(参数…)
#返回装饰器
def return_decorator(flag):
def decorator(func):
def inner(a, b):
if flag=="+":
print("正在努力执行加法计算")
else:
print("正在努力执行减法计算")
func(a, b)
return inner