闭包
内层函数对外层函数变量的引用,并返回.(变量非全局变量).
鉴定是否闭包:print(内层函数名.__closure__)
返回一个类似地址是闭包,返回None非闭包
闭包的作用
当程序执行时,遇到函数执行会在内存中开辟一个局部名称空间,如果此函数内部形成闭包,就不会随着函数结束而消失.
迭代器
可迭代对象:
对象内部含有__iter__
方法是可迭代对象 ,满足可迭代协议. (str,list,dict,tuple,set,range()…)
可迭代对象判断方法:
方法一:
s1='strs'
print('__iter__'in dir(s1))#s1中有没有__iter__方法
方法二:
from collections import Iterable
print(isinstance('abc',Iterable))#True
迭代器
对象内部中含有__iter__
和__next__
方法的,就是迭代器.
迭代器判断方法:
f=open('register',encoding='utf-8')
print('__iter__'in dir(f)) #True
print('__next__'in dir(f)) #True
可迭代对象不能进行取值,可转化为迭代器,迭代器可取值
lis=[1,2,3]#可迭代对象
#两种方法:
ite=lis.__iter__()#转化为迭代器
ite=iter(lis)#转化为迭代器
print(ite.__next__())#取值
1. 可迭代对象不一定是迭代器,迭代器一定是可迭代对象
2. 迭代器非常节省内存
3. 迭代器单向取值,且只取一个值
生成器
一边循环一边计算的机制,称为生成器:generator。
生成器仅仅保存了一套生成数值的算法,并且没有让这个算法现在就开始执行,而是什么时候调它,它什么时候开始计算一个新的值,并给你返回。
生成器的本质就是迭代器.
理解的关键在于:下次迭代时,代码从yield的下一条语句开始执行
为什么要有生成器
列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。
如:仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
简单一句话:想得到庞大的数据,又想让它占用空间少,那就用生成器
创建生成器
方法一:
把一个列表生成式的[ ]改成( ),就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
方法二, 如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。调用函数就是创建了一个生成器(generator)对象。