百度百科上的定义:
闭包就是能够读取其他函数内部变量的函数。只有函数内部的子函数才能读取局部变量,所以闭包可以理解成 “定义在一个函数内部的函数” 。
在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
举个栗子,例子1
def sum(a):
def add(b):
return a + b
return add
num = sum(2)
print(num)
print(type(num))
print(num.__name__) # 打印函数的名称,从结果可以看出,返回函数add
# 运行结果
<function sum.<locals>.add at 0x0000000001E11048>
<class 'function'>
add
解析说明
如果再一个函数内部嵌套了另外一个函数(将外部的函数和内部的函数成为外函数和内函数),函数中引用了外函数中的变量,并且外函数的返回值是内函数,称之为 闭包。
上面的列子:
sum 为外函数,add 为内函数;
内函数 add 引用了外函数 sum 的变量a;
外函数 sum 返回内函数 add;
符合闭包的定义。
普通函数
一般情况下,函数调用结束后,函数内定义的变量将不可使用。
# -*- coding:utf-8 -*-
def do_sth():
temp = 9
print(temp)
do_sth() # 调用函数,打印 temp
print(temp) # 会报错,提示temp没定义, NameError: name 'temp' is not defined
闭包
对于闭包而言,外函数调用结束后,外函数中被内函数引用的变量仍然可用,
因为外函数中被内函数引用的变量会被绑定到内函数的特殊属性__closure__中。
def outer():
a = 9
def inner():
print(a)
return inner
outer()() # 9
外函数中被内函数引用的变量会被绑定到内函数的特殊属性__closure__中。
def outer():
a = 9
def inner():
print(a)
return inner
result = outer()
print(result.__closure__) # (<cell at 0x0000000001DEF978: int object at 0x000007FED6CF7D40>,) 是一个元祖
print(result.__closure__[0].cell_contents) # 9
# closure:闭包
# cell_contents: 单元格内容
栗子2
def outer():
a = 9
def inner():
a += 1
return inner
outer()()
# UnboundLocalError: local variable 'a' referenced before assignment
# UnboundLocalError:赋值前引用的局部变量“a”
"""
a += 1 相当于 a = a + 1
重新定义一个变量 a, 把外函数中的变量 a 给屏蔽了;
当计算等号右边的 a + 1 时,新定义的变量 a 还没有被赋值,因此程序会报错
"""
栗子3
def outer():
a = [5] # a 为列表,列表是可变类型对象
def inner():
a[0] = 9 # 此时 a 没有波浪线了,修改列表 a 的对象的值,把列表的值改为 9
print(a)
return inner
outer()() # [9]
对比例2和例3,得出的结论:
在默认情况下,在内函数中不能修改外函数中的变量引用的对象,
如果引用的对象是可变类型的,可以修改对象的内容。
如果想在内函数中修改外函数中的变量所引起的的对象,要怎么办?
def outer():
a = 10 # a 为列表,列表是可变类型对象
def inner():
nonlocal a
a += 1
print(a)
return inner
outer()() # 11
如果想在内函数中修改外函数中的变量所引起的的对象,可以在内函数中使用关键字
nonlocal对变量进行声明,从而表明在内函数中并没有重新定义一个新的同名变量,
而是使用外函数中该名称的变量。
闭包经典面试题
1、下列程序是否是闭包,是否能正常运行
def outer():
n = 2
def inner(x):
n += 1
return x ** n
return inner
p = outer()
print(p(3))
解析:是闭包,但是运行会报错
修改:
def outer():
n = 2
def inner(x):
nonlocal n
n += 1
return x ** n
return inner
p = outer()
print(p(3)) # 27
2、以下程序执行的结果是多少
def outer():
n = 2
L = []
for i in range(1, 3):
def inner():
return i ** n
L.append(inner)
return L
f1, f2 = outer()
print(f1()) # 4
print(f2()) # 4
python的函数只有在执行时,才会去找函数体里的变量的值,也就是说你连形参都不确定,
你咋知道i为几呢?,在这里,你只需要记住如果你连形参都不确定,python就只会记住最后一个i值。
------分界线------
* 学到知识
* 积累经验
* 太高思维
* 锻炼心性
* ......
------
有了这个思维,
你自然会变得更好,
结果就自然会变好,
钱自然会来找你,