什么是闭包
# 概念:内嵌函数引用了外层函数的变量然后返回内嵌函数就称之为闭包。
# 总结一下,创建一个闭包必须满足以下几点:
# 1. 必须有一个内嵌函数
# 2. 内嵌函数必须引用外部函数中的变量
# 3. 外部函数的返回值必须是内嵌函数
闭包的判断,外层打印执行函数f().__closure__,闭包返回内存地址,非 闭包返回None
x=1
def f1():
x=1000
y=1
def f2():
print(x)
print(y)
return f2
f=f1()
#执行f2
f()
#返回内存地址, 判定是不是闭包
print("f.__closure__:",f.__closure__)
# (<cell at 0x1097a1348: int object at 0x109351a60>, <cell at 0x1097a13a8: int object at 0x109351a40>)
x=2
def f2(x):
y=1
def f2():
print(x)
print(y)
return f2
f=f2(2)
#执行f2
f()
#返回内存地址, 判定是不是闭包
print("f.__closure__:",f.__closure__)
# (<cell at 0x1097a1348: int object at 0x109351a60>, <cell at 0x1097a13a8: int object at 0x109351a40>)
def f3():
def f2():
x=1000
print(x)
return f2
f=f3()
#执行f2
f()
#返回内存地址, 判定是不是闭包
print("没有外部变量 f.__closure__:",f.__closure__)
# 返回None
闭包的作用,优缺点
# 闭包的作用
# 1.使用闭包可以访问函数中的变量。
# 2.可以使变量长期保存在内存中,生命周期比较长。
# 优点:封装代码提高重用性,安全
# 缺点:重点是函数运行后并不会被撤销,滞留内存
# 闭包不能滥用,否则会导致内存泄露(内存无法释放),影响网页的性能。
# 闭包使用完了后,要立即释放资源,将引用变量指向null。
# 关于内存泄漏和内存溢出
# 内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,
# 造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
# 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
几个案例
# 如下返回,返回的是三个结果,这三个结果是无法调用,能调用的只有函数,所以你必须返回函数
def count():
fs = []
for i in range(1, 4):
x=i*i
fs.append(x)
return fs
print(count())
# f1, f2, f3 = count()
# print(f1(), f2(), f3())
# 返回三个函数的列表,直接把函数名添加进去即可
def count():
fs = []
for i in range(1, 4):
def f(m=i):
return m * m
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1, f2, f3)
print(f1(), f2(), f3())
def mul():
z=[lambda x:i*x for i in range(4)]
return z
print([j(2) for j in mul()])
# x是闭包变量,[6,6,6,6]
def mul():
z=[lambda x,i=i:i*x for i in range(4)]
return z
print([j(2) for j in mul()])
惰性计算
x=1
def f1():
x=1000
y=1
def f2():
print(x)
y
return f2
f=f1()
#执行f2
f()
#返回内存地址, 判定是不是闭包
print(f.__closure__)
#返回内部x,y
print(f.__closure__[0].cell_contents)
print(f.__closure__[1].cell_contents)
#牛逼之处,惰性计算,想要的时候加个括号
from urllib.request import urlopen
def get(url):
r=print(urlopen(url).read())
return r
py=get("http://www.baidu.com")
def spi(url):
def spider():
print(urlopen(url).read())
return spider
spider1=spi("http://www.baidu.com")
#需要的时候执行
spider1()
print(spider1.__closure__)