1.什么是迭代器:
迭代器简单来讲就是迭代取值的工具
迭代是一个重复的过程,每一次重复都是基于上一次的结果而来,单纯的重复并不是迭代。
while True:
print('x') #这种单纯的循环不是迭代
我们尝试用while循环实现迭代过程:
l = ['a', 'b', 'c']
def iterator(item)
i = 0
while i < len(item):
print(l[i])
i += 1
iterator(l)
2.为什么要有迭代器?
基于索引取值的数据类型只适用于列表、元组、字符串类型
那么对于没有索引的字典、集合、文件等,则不适用
所以需要找到一种通用的并且不依赖索引的迭代取值方式---> 迭代器
至此,假设我们从来不知道for循环是什么东西。
那我们如何使用现有的知识模拟迭代的过程呢
s = 'hello'
def iterator(item):
i = 0
while i < len(item):
print(item[i])
i += 1
iterator(s)
我们先简单了解下几个概念:
可迭代对象:先简单解释为在python中但凡内置有__iter__方法的对象都是可迭代对象,字符串、元组、列表、字典、集合、文件都是可迭代对象,即上述类型的数据都内置有___iter___方法使用
迭代器对象:指的是既内置有__iter__方法,又内置有__next__方法的对象
执行可迭代对象的__iter__方法得到的就是内置的迭代器对象
文件对象本身就是迭代器对象
迭代器对象一定是可迭代对象,反之则不然
我们看个简单的例子加深以上概念的印象:
info = {'name': 'zhangsan', 'age':24}
info__iter = info.__iter__() #这一行是由内置__iter__方法从可迭代对象中取出迭代器对象
print(info_iter)
res1 = info__iter.__next__() #假设我们不知道循环,继续取值
print(res1)
res2 = info__iter.__next__()
print(res2)
res3 = info__iter.__next__() #一旦迭代器将可迭代对象取值完毕,再继续取值就会跑出StopIteration的异常
我们假设已经学习了异常处理的知识,改进如下:
info = [1, 2, 3, 4]
info__iter = info.__iter__()
while True:
try:
print(info__iter.__next())
except StopIteration:
break
现在来介绍下for循环,for循环也叫迭代器循环
for循环的对象一定要是可迭代对象
info = {'name':'zhangsan', 'age': 21, 'sex':'male'}
for i in info: #其实等同于info__iter = info.__iter__()
print(i)
f = open('a.txt', 'r')
for k in f:
print(k)
我们再来说一下什么是迭代器对象呢?
迭代器对象:指的是既内置有__iter__方法,又内置有__next__方法的对象。
这里我们还要注意:执行迭代器对象的__next__得到的是迭代器的下一个值;执行迭代器对象的__iter__得到的仍然是迭代器本身。
info = [1, 2, 2, 3,]
iter__info = info.__iter__()
print(iter__info)
print(iter__info is iter__info.__iter__() is iter__info.__iter__().__iter__().__iter__().__iter__()) #迭代器对象的__iter__得到的仍然是迭代器本身
总结迭代器对象的优缺点:
优点:
提供了一种通用的、可以不依赖索引的迭代取值方式
迭代器对象更加节省内存
缺点:
迭代器的取值不如按照索引取值的方式灵活,因为它只能往后取,不能往前退。
无法预测迭代器值的个数。
什么是生成器:在函数内凡是出现yield 关键字,再掉用该函数就不会执行函数体代码,会返回一个值,该值就被称为生成器。
生成器是一种自定义的迭代器
下面我们看看如何使用
def func():
print('first')
yield 1
print('second')
yield 2
print('third')
yield 3
g = func() #g是一个迭代器
res1 = next(g) # 用内置方法next执行一次迭代器对象
print(res1)
res2 = next(g)
print(res2)
我们尝试着自己造一个range函数出来:
def my_range(start, stop, step = 1):
while start < stop:
yield start #将函数暂停
start += step
g = my_range(1, 9, 2)
for i in g:
print(i)
总结下yield的功能:提供一种自定义迭代器的方式;yield可以暂停住函数,并返回值。
与return的相同点是:都用在函数内,可以有返回值,无类型和个数限制
不同点是:return只能返回一个值,yield能返回多次值
python中三元表达式格式如下:
为真时结果 if 判定条件 else 为假时结果
1 if 10>3 else 0
结果为1
根据现有的列表高效的创建新列表,是迭代机制的一种应用,具体应用如下:
l = [i for i in range(1,11)]
我们可以很快造出一个从1到10的列表。
l1 = ['a', 'b', 'c', 'd', ]
l1 = [k.upper() for k in l1] #将l1中的元素改为大写
l2 = [i ** 2 for i in range(10) if i > 5] #造一个1到9的列表,其中大于5的元素全部取平方
与列表解析式相似,要注意的是字典是以键值对存取数据
现在有两个列表,通过zip函数可以将列表的元素对应存储起来,然后用字典解析存储成键值对,如下:
keys -=['name', 'age', 'sex']
values = ['zhangsan', 25, 'male']
dic = {k:v for k, v in zip(keys, values)}
print(dic)
生成器表达式
g = (i for i in range(10))
print(g)
print(next(g))
print(next(g))#自定义生成器
打印某个文件中字符数最多的一行:
with open('a.txt', encoding = 'utf-8')as f:
nums = (len(line) for line in f)
print(max(nums))
print(max(nums))#试试这两处打印都会有什么结果呢?