迭代器
武功秘籍
迭代
迭代即更新换代 每次的更新都必须依赖于上一次的结果
'''迭代其实给我们提供了一种不依赖索引取值的方式'''
可迭代对象
内置有__iter__方法的都称之为可迭代对象
内置的意思是可以通过点的方式直接查看到的
"""
针对双下滑线开头 双下滑线结尾的方法 最为专业标准的读法为
双下方法名
面向对象的时候为了与隐藏变量区分开
"""
n = 1 while True: n+=1 print(n) l = [11,22,33,44,55,66] n = 0 while n < len(l): print(l[n]) n += 1 i = 12 # 没有 f = 11.11 # 没有 s = 'jason' # 有 l = [111,22,33,4] # 有 d = {'username':'jason','pwd':123} # 有 t = (11,22,33) # 有 se = {11,22,33} # 有 b = True # 没有 file = open(r'a.txt','w',encoding='utf8') """ 含有__iter__的有 字符串 列表 字典 元组 集合 文件对象 上述通常为可迭代对象 """ print(d) print(d.__iter__()) # 等价于调用了一个内置方法 d.get() print(iter(d)) print(d.__len__()) print(len(d))
可迭代对象调用__iter__方法会变成迭代器对象(老母猪)
__iter__方法在调用的时候还有一个简便的写法iter()
一般情况下所有的双下方法都会有一个与之对应的简化版本 方法名()
迭代器对象
即含有__iter__方法 又含有__next__方法
如何生成迭代器对象
让可迭代对象执行__iter__方法
文件对象本身即是可迭代对象又是迭代器对象
迭代器对象无论执行多少次__iter__方法 还是迭代器对象(本身)
迭代器给我们提供了不依赖于索引取值的方式
i = 12 # 没有 f = 11.11 # 没有 s = 'jason' # 有 l = [111,222,333,444] # 有 d = {'username':'jason','pwd':123} # 有 t = (11,22,33) # 有 se = {11,22,33} # 有 b = True # 没有 file = open(r'a.txt','w',encoding='utf8') res = s.__iter__() # 转成迭代器对象 print(res.__next__()) # 迭代器对象执行__next__方法其实就是在迭代取值(for循环) print(res.__next__()) print(res.__next__()) print(res.__next__()) print(res.__next__()) res = d.__iter__() # 转成迭代器对象 print(res.__next__()) # 迭代器对象执行__next__方法其实就是在迭代取值(for循环) print(res.__next__()) print(res.__next__()) # 取完元素之后再取会"报错" # 易错 print(d.__iter__().__next__()) # username print(d.__iter__().__next__()) # username print(d.__iter__().__next__()) # username print(d.__iter__().__next__()) # username print(d.__iter__().__next__()) # username print(d.__iter__().__next__()) # username
l1 = [1,2,3,4,5,6,7,8,9,11,22,33,44,55] # 循环打印出列表中每个元素 但是不能使用for循环 __next__() next() # 1.先将列表转为迭代器对象 res = l1.__iter__() # 2.循环执行__next__取值 while True: print(res.__next__()) for i in l1: print(i)
for循环内部原理
1.将关键字in后面的数据先调用__iter__方法转为迭代器对象
2.循环执行__next__方法
3.取完之后__next__会报错 但是for循环会自动捕获该错误并处理
res = 数据.__iter__()
while True:
try:
检测代码是否会报错
res.__next__()
except:
pass
如果报错了则自动处理掉并结束while循环
d = {'name':'jason','pwd':123,'hobby':'read'}
res = d.__iter__() # StopIteration
while True:
try:
print(res.__next__())
except StopIteration as e:
break
for i in d:
print(i)
迭代取值
优点:
不依赖于索引的一种通用取值方式
缺点:
取值的顺序永远都是固定的从左往右 无法重复获取
索引取值
缺点:
需要提供有序容器类型才可取值(不是一种通用的方式)
优点:
可以重复取值
# 定义阶段就是一个普通函数 def my_ge(): print('first') yield 123,222,333 print('second') # yield 456,444,555 """ 当函数体内含有yield关键字 那么在第一次调用函数的时候 并不会执行函数体代码 而是将函数变成了生成器(迭代器) """ # 调用函数:不执行函数体代码 而是转换为生成器(迭代器) res = my_ge() ret = res.__next__() # 每执行一个__next__代码往下运行到yield停止 返回后面的数据 print(ret) ret = res.__next__() # 再次执行__next__接着上次停止的地方继续往后 遇到yield再停止 print(ret)
def my_range(start, stop=None, step=1): if not stop: stop = start start = 0 while start < stop: yield start start += step res = my_range(10) for i in res: print(i) res = my_range(1,10) for i in res: print(i) res = my_range(1,10,3) for i in res: print(i)
.send(值)传给yield值
def eat(name): print('%s 准备干饭!!!'%name) while True: food = yield print('%s 正在吃 %s' % (name, food)) res = eat('jason') # 并不会执行代码 而是转换成生成器 res.__next__() res.send('肉包子') res.send('盖浇饭')
yield
1.可以返回值(支持多个并且组织成元组)
2.函数体代码遇到yield不会结束而是"停住"
3.yield可以将函数变成生成器 并且还支持外界传值
return
1.可以返回值(支持多个并且组织成元组)
2.函数体代码遇到return直接结束
l = [11, 22, 33, 44, 55, 66, 77, 88, 99] res = [i+1 for i in l if i!=44] print(res) res1 = (i+1 for i in l if i!=44) """ 生成器表达式内部的代码只有在迭代取值的时候才会执行 """ print(res1.__next__()) print(res1.__next__()) print(res1.__next__()) """ 迭代器对象 生成器对象 我们都可以看成是"工厂" 只有当我们所要数据的时候工厂才会加工出"数据" 上述方式就是为了节省空间 """ # 求和 def add(n, i): return n + i # 调用之前是函数 调用之后是生成器 def test(): for i in range(4): yield i g = test() # 初始化生成器对象 for n in [1, 10]: g = (add(n, i) for i in g) """ 第一次for循环 g = (add(n, i) for i in g) 第二次for循环 g = (add(10, i) for i in (add(10, i) for i in g)) """ res = list(g) print(res) #A. res=[10,11,12,13] #B. res=[11,12,13,14] #C. res=[20,21,22,23] #D. res=[21,22,23,24]
END

浙公网安备 33010602011771号