最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

python函数 | 闭包函数

XAMPP案例 admin 431浏览 0评论
目录
闭包的定义闭包示例判断是否是闭包

详解
闭包的定义
闭包的定义:
  • 闭包是嵌套在函数中的函数;
  • 闭包必须是内层函数对外层函数的变量(非全局变量)的引用。
  • 被引用的非全局变量叫做自由变量,会与内层函数产生一个绑定关系,不会在内存中消失。
闭包的作用:

  • 保存局部信息不被销毁,保证数据的安全性。

闭包的应用:

  • 可以保存一些非全局变量,但是不易被销毁、被改变的数据;
  • 装饰器。
闭包示例
示例:完成一个计算不断增加的系列值的平均值的需求。
例如:整个历史中某个车场的日平均收入。
日平均收入就是从这个车场一出现开始,每天记录当天的收入,然后计算平均值(平均值要考虑直至目前为止所有的日收入)

第一天收入为:1000元,日平均收入:1000元
第二天收入为:1100元,日平均收入:(1000 + 1100)/2 元
第三天收入为:1200元,日平均收入:(1000 + 1100 + 1200)/3 元......
初始解决方案(普通函数):
incomes = []
def average_income(new_income):
    incomes.append(new_income)
    return sum(incomes) / len(incomes)
    
print(average_income(1000))  # 1000.0
print(average_income(1100))  # 1050.0
print(average_income(1200))  # 1100.0
这个解决方案基本上完成了需求,但是这个代码相对来说是不安全的,因为incomes是一个全局变量,只要是全局作用域的任何地方,都可能对这个列表进行改变。
incomes = []
def average_income(new_income):
    incomes.append(new_income)
    return sum(incomes) / len(incomes)
    
print(average_income(1000))  # 1000.0
print(average_income(1100))  # 1050.0
incomes.append(1)  # 如果对列表数据进行了改变,就会影响之后计算的日平均收入
print(average_income(1200))  # 825.25
把incomes放在函数中也不行,虽然incomes是局部变量,数据相对安全了,但是这样计算的结果是不正确的,因为每次执行函数,都会开启一个局部命名空间,随着函数的结束而消失,即每次执行函数时,都会重新创建这个列表,就无法保存之前的日收入了。
def average_income(new_income):
    incomes = []
    incomes.append(new_income)
    return sum(incomes) / len(incomes)

print(average_income(1000))  # 1000.0
print(average_income(1100))  # 1100.0
print(average_income(1200))  # 1200.0
这种情况下,就需要用到闭包来解决这个需求了。
 
最终解决方案(闭包函数):
def average_income():
    incomes = []
    def avg_income(new_income):
        incomes.append(new_income)
        return sum(incomes) / len(incomes)
    return avg_income

avg = average_income()
print(avg(1000))  # 1000.0
print(avg(1100))  # 1050.0
print(avg(1200))  # 1100.0
这个解决方案是在函数中嵌套了一个函数。avg这个变量接收的是avg_income函数名,也就是avg_income函数对应的内存地址,执行了三次avg,也就是执行了三次avg_income函数。内层函数对外层函数非全局变量进行引用,就会形成闭包,avg_income函数就是闭包。

变量incomes是average_income函数的局部变量,没有随着average_income函数的执行结束之后而消失,是因为此区域形成了闭包,变量incomes变成了自由变量,会与avg_income函数产生一个绑定关系,就不会在内存中消失。也就是说,每次调用avg对应的avg_income函数时,都可以引用到这个自由变量,这就是闭包。

 
判断是否是闭包
1.根据闭包的定义判断是否是闭包。
  • 闭包是嵌套在函数中的函数;
  • 闭包必须是内层函数对外层函数的变量(非全局变量)的引用。
# 例一:是闭包
def wrapper():
    a = 1
    def inner():
        print(a)
    return inner
ret = wrapper()
# 例二:不是闭包
a = 1
def wrapper():
    def inner():
        print(a)
    return inner
ret = wrapper()
# 例三:是闭包
def wrapper(a,b):
    def inner():
        print(a)
        print(b)
    return inner
a = 1
b = 2
ret = wrapper(a,b)
2.利用函数的属性,可以获取到此函数是否拥有自由变量,如果拥有自由变量,就可以证明是闭包函数。
def average_income():
    incomes = []
    def avg_income(new_income):
        incomes.append(new_income)
        return sum(incomes) / len(incomes)
    return avg_income

avg = average_income()
print(avg(1000))  # 1000.0
print(avg(1100))  # 1050.0
print(avg(1200))  # 1100.0


'''
函数名.__code__.co_freevars 
查看函数的自由变量
'''
print(avg.__code__.co_freevars)  # ('incomes',)


'''
函数名.__code__.co_varnames 
查看函数的局部变量
'''
print(avg.__code__.co_varnames)  # ('new_income',)


'''
函数名.__closure__ 获取具体的自由变量对象(cell对象)
cell_contents 查看自由变量具体的值
'''
print(avg.__closure__)  # (<cell at 0x000002B018FAB768: list object at 0x000002B018C451C8>,)
print(avg.__closure__[0].cell_contents)  # [1000, 1100, 1200]

转载请注明:XAMPP中文组官网 » python函数 | 闭包函数

您必须 登录 才能发表评论!