一、什么是可迭代对象?
方法一、dir(被测对象),如果他含有__iter__,那这个对象就叫做可迭代对象
s = "abc" print("__iter__" in dir(s)) #True print("__iter__" in dir(333)) #False
遵循可迭代协议
1.可迭代协议:可以被迭代要满足要求的就叫做可迭代协议。内部实现了__iter__方法
iterable:可迭代的------对应的标志
什么叫迭代?:一个一个取值,就像for循环一样取值
字符串,列表,元组,集合,字典都是可迭代的
2、迭代器协议:内部实现了__iter__,__next__方法
迭代器大部分都是在python的内部去使用的,我们直接拿来用就行了
迭代器的优点:如果用了迭代器,节约内存,方便操作
dir([1,2].__iter__())是列表迭代器中实现的所有的方法,而dir([1,2])是列表中实现的所有方法,都是以列表的方式返回给我们,为了方便看清楚,我们把他们转换成集合,然后取差集,然而,我们看到列表迭代器中多出了三个方法,那么这三个方法都分别是干什么的呢?
print(dir([1,2].__iter__()))#查看列表迭代器的所有方法 print(dir([1,2]))#查看列表的所有方法 print(set(dir([1,2].__iter__()))-set(dir([1,2])))
iter_list=[1,2,3,4,5,6].__iter__() print(iter_list.__length_hint__())#获取迭代器中元素的长度 print(iter_list.__setstate__(4))#根据索引指定从哪里开始迭代 print(iter_list.__next__()) print(iter_list.__next__()) print(iter_list.__next__())#一个一个的取值 print(next(iter_l)) next(iter_list)这个方法和iter_list.__next__()方法一样, 推荐用next(iter_list)这个
方法二、测试是迭代器还是可迭代对象
type 只能判断数据类型
例子1
l = [1,2,3]
l_iter = l.__iter__()
from collections import Iterable
from collections import Iterator
print(isinstance(l,Iterable)) #True #判断他是可迭代对象
print(isinstance(l,Iterator)) #False #判断他是迭代器
print(isinstance(l_iter,Iterator)) #True
print(isinstance(l,list)) #True
例子:range 是可迭代对象还是迭代器
i = range(10) # print( "__iter__" in dir(range(10))) #True # print("__next__" in dir(range(10))) #False from collections import Iterable from collections import Iterator print(isinstance(i,Iterable)) #判断他是可迭代对象 print(isinstance(i,Iterator)) #判断他是迭代器
二、可迭代对象 iterable 与 迭代器 iterator 有什么关系
可迭代对象---> 转换成迭代器
可迭代对象__iter__() --->迭代器
s = "abc" s1 = s.__iter__() print(s1) #<str_iterator object at 0x00000228E73F7278> 遵循得带协议
li1 = [1,2,3,5] print("__iter__" in dir(list)) #True li2 = li1.__iter__() print("__next__" in dir(li2)) #True print(list2.__next__()) print(list2.__next__()) print(list2.__next__()) print(list2.__next__())
三、迭代器取值
只含有__iter__方法的数据是可迭代对象
含有__iter__方法,并且含有__next__方法的数据是迭代器
s2 = "abc" s3 = s2.__iter__() #<str_iterator object at 0x00000128D84A7828> # # print(s3.__next__()) # print(s3.__next__()) # print(s3.__next__()) print("__iter__" in dir(s2)) #True print("__next__" in dir(s2)) #False print("__iter__" in dir(s3)) #True print("__next__" in dir(s3)) #True
l = [1,2,3,4,5] print("__iter__" in dir(l)) #True print("__next__" in dir(l)) #False l2 = l.__iter__() print(l2.__next__) print(l2.__next__) print(l2.__next__) print(l2.__next__) print(l2.__next__)
四、迭代器的意义
1.迭代器节省内存
2.迭代器惰性机制
3,迭代器不能反复,一直向下执行.
五、for循环的机制.
内部含有__iter__方法,他会将可迭代对象先转化成迭代器,
然后在调用__next__方法.
他有异常处理的方法.
用while 循环模拟 for 循环机制
li = [1,2,3] li_iter = li.__iter__() while True: try: #遇到错误,try一下 print(li_iter.__next__()) except StopIteration: break 有异常处理能力
总结:
可迭代对象:str list tuple dict set range
迭代器: 文件句柄,map
六、生成器
(一)生成器的本质是迭代器,生成器是自己用python写的迭代器
1,可以用生成器函数
2,可以用各种推导式构建迭代器.
3,可以通过数据转化.
(二)
普通函数
例子1.1
def func():
print(111)
return 222
ret = func()
print(ret)
生成器函数,生成器
return yield 区别
return 返回给调用者值,并结束此函数.
yiled 返回给调用者值,并将指针停留着当前位置.
例子1.2
def gener(): print("aaa") yield 222 #yield是表示是生成器函数 print("bbb") yield 333 print("ccc") g = gener() #不是执行函数,是产生生成器 print(g.__next__()) # 一个next,一个yield,并且光标停留在yield后 print(g.__next__())
例子2.1: def cloth(): for i in range(100): print(i) cloth() 例子2.2: 方法一、 def cloth(): for i in range(1000): yield "衣服%s"%i f = cloth() print(f.__next__()) #衣服0 print(f.__next__()) #衣服1 方法二、 def cloth(): for i in range(1000): yield "衣服%s"%i f = cloth() for i in range(50): print(f.__next__())
(三)面试题
send
1.send 和 next 功能一样
2.给上一个 yiled 整体 发送一个值
3.获取第一个值的时候,不能用send,只能用next
可以给上一个yiled整体发送一个值
def gener(): print("aaa") yield 222 print("bbb") count = yield 333 print("----->",count) yield "aaa" yield 333 g = gener() print(g.__next__()) print(g.send(None)) print(g.send("AAAA"))
七、列表推导式
(一)通过数据转换
list() tuple() 可以将生成器对象转换
生成器 = 生成器对象
(二)列表推导式
[变量(加工后的数据) for 变量 i in 可迭代的数据类型 ] 列表的推导式, 循环模式
[变量(加工后的数据) for 变量 i in 可迭代的数据类型 if 条件] 列表的推导式, 筛选模式
li2 = ["python%s期"%i for i in range(1,11)] print(li2)
30以内能被3整除的数的平方
li1 = [i**2 for i in range(31) if i%3 == 0 ] print(li1)
八、生成器表达式
类似于列表推倒式,就是把列表推导式的【】改为了()
l=[{'name':'v1','age':'22'},{'name':'v2'}] name_list=(dic['name'] for dic in l) #吧列表生成器的[]改成() print(name_list) #取出的是一个生成器,而不是要取得值,所以得加上next print(next(name_list)) print(next(name_list))
九、列表推导式,生成器表达式的作用
1,列表推导式比较直观,占内存
2,生成器表达式不容易看出内容,省内存.
3.python不但使用迭代器协议,
让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。
例子1.将一个字典的key 和 value 对调
前提是value是不可变数据类型,因为键是不可变数据类型
mcase = {"a" : 10 ,"b" : 34} mcasw_frequency = {mcase[k]:k for k in mcase} print(mcasw_frequency)
例子2
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] f = [a for i in names for a in i if a.count("e") == 2] print(f)