可迭代对象和迭代器的解释以下:python
''' 什么是对象?Python中一切皆对象,以前咱们讲过的一个变量,一个列表,一个字符串,文件句柄,函数名等等均可称做一个对象,其实一个对象就是一个实例,就是一个实实在在的东西。那么什么叫迭代?其实咱们在平常生活中常常遇到迭代这个词儿,更新迭代等等,迭代就是一个重复的过程,可是不能是单纯的重复(若是只是单纯的重复那么他与循环没有什么区别)每次重复都是基于上一次的结果而来。好比你爹生你,你生你爹,哦不对,你生你儿子,你儿子生你孙子等等,每一代都是不同的;还有你使用过得app,微信,抖音等,隔一段时间就会基于上一次作一些更新,那么这就是迭代。可迭代对象从字面意思来讲就是一个能够重复取值的实实在在的东西。 ''' ''' 1.可迭代对象: 字面意思:对象?python中一切皆对象。一个实实在在存在的值,就是对象 可迭代?:更新迭代。重复的,循环的一个过程,更新迭代每次都有新的内容。 能够进行循环更新的一个实实在在的值。 专业角度:可迭代对象?内部含有__iter__方法的对象,可迭代对象。 目前学过的可迭代对象?str list tuple dict set range 文件句柄 2.获取对象的方法 dir() 3.判断一个对象是不是可迭代的对象 s1 = 'adasda' l1 = [1, 2, 3] print(dir(s1)) # 获取全部的方法。 print(dir(l1)) # 获取列表的全部的方法。 print('__iter__' in dir(s1)) # True print('__iter__' in dir(range(10))) # True # 输出的结果:True表示是可迭代对象,False表示不是可迭代对象。 4.小结 字面意思:能够进行循环更新的一个实实在在的值。 专业角度:内部含有__iter__方法的对象,表示是可迭代对象。 判断一个对象是否是可迭代对象:__iter__方法是否在dir(对象)中。 str list tuple dict set range 优势:1.存储的数据直接能显示,比较直观。2.拥有的方法比较多,操做方便。 缺点:1.占用内存。2.不能直接经过for循环,不能直接取值(索引,key除外)。可是在实际的时候咱们列表和字符串等等可迭代对象能够经过for循环取值,是由于咱们封装了__next__方法,变成了迭代器。那么就能够直接经过for循环取值。 5.迭代器 (1)迭代器的定义 字面意思:更新迭代,器:工具。可更新迭代的工具 专业角度:内部含有__iter__方法而且含有__next__方法的对象就是迭代器。 (2)判断一个对象是不是是迭代器 __iter__方法 and __next__方法是否在不在dir(对象)中 咱们目前学的迭代器只有文件句柄。 6.可迭代对象如何转换为迭代器 iter()将可迭代对象转换为迭代器---》iter([1,2,3]) s1 = 'asdasdcsadfc' obj = iter(s1) # s1.__iter__() print(obj) # <str_iterator object at 0x0000022ED5F3CF08> print(next(obj)) # next(obj) print(obj.__next__()) # obj.__next__() 迭代器的取值 s1 = 'sdwfe' obj = iter(s1) # 这里将可迭代对象转换为迭代器 print(obj) # <str_iterator object at 0x000001F7ACF4CA88> print(next(obj)) # s print(next(obj)) # d print(next(obj)) # w print(next(obj)) # f print(next(obj)) # e # print(next(obj)) # StopIteration # Traceback (most recent call last): # File "D:/Program Files (x86)/DjangoProjects/basic/day11/04 迭代器.py", line 96, in <module> # print(next(obj)) # StopIteration # 迭代器利用next取值:一个next取对应的一个值,若是迭代器里面的值取完了,还要next, # 那么就报StopIteration的错误。 l1 = [11, 22, 33, 44, 55, 66] obj = iter(l1) # 对列表进行操做造成了迭代器 print(next(obj)) print(next(obj)) print(next(obj)) print(next(obj)) print(next(obj)) print(next(obj)) 输出的结果为: 11 22 33 44 55 66 ''' ''' 小结 (1)可迭代对象: 字面意思:能够进行循环更新的一个实实在在的值。 专业角度:内部含有__iter__方法的对象,表示是可迭代对象。 判断一个对象是否是可迭代对象:__iter__方法是否在dir(对象)中。 str list tuple dict set range 优势:1.存储的数据直接能显示,比较直观。2.拥有的方法比较多,操做方便。 缺点:1.占用内存。2.不能直接经过for循环,不能直接取值(索引,key除外)。可是在实际的时候 咱们列表和字符串等等可迭代对象能够经过for循环取值,是由于咱们封装了__next__方法,变成了迭代器。那么就能够直接经过for循环取值。 (2)迭代器: 字面意思:更新迭代,器:工具。可更新迭代的工具 专业角度:内部含有__iter__方法而且含有__next__方法的对象就是迭代器。 优势:1.节省内存。迭代器在内存中至关于只占一个数据的空间:由于每次取值都上一条数据会在内存释放,加载当前的此条数据。2.惰性机制。next一次,取一个值,毫不过多取值。 缺点:1.速度慢:用时间换空间。2.不走回头路,不直观。3.操做方法单一。 可迭代对象与迭代器的对比 (几百万个对象,8G内存是能够接受的,承受的) 可迭代对象是一个操做方法比较多,比较直观的,存储数据相对少的一个数据集。 当你侧重于对于数据能够灵活处理,而且内存空间足够,将数据集设置为可迭代对象是明确的选择 当你的数据量大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集 设置为一个迭代器是一个不错的选择。 ''' l1 = [1, 2, 3, 4, 5, 6] obj = iter(l1) # obj = l1.__iter__() for i in range(2): print(next(obj)) for i in range(2): print(next(obj)) # 输出的结果为: # 1 # 2 # 3 # 4
# while循环模拟for循环(这个是面试题,直接手写面试题) # 刚才咱们提到了,for循环的循环对象必定要是可迭代对象,可是这不意味着可迭代对象就能够取值,由于for循环的内部机制是:将可迭代对象转换成迭代器,而后利用next进行取值,最后利用异常处理处理StopIteration抛出的异常。 l1 = [1, 2, 3, 4, 5, 6] # 1 将可迭代对象转化成迭代器 obj = iter(l1) # 2,利用while循环,next进行取值 while 1: # 3,利用异常处理终止循环 try: print(next(obj)) except StopIteration: break
咱们今天比较深刻的了解了可迭代对象与迭代器,接下来咱们说一下这二者之间比较与应用:面试
可迭代对象:是一个私有的方法比较多,操做灵活(好比列表,字典的增删改查,字符串的经常使用操做方法等),比较直观,可是占用内存,并且不能直接经过循环迭代取值的这么一个数据集。微信
应用:当你侧重于对于数据能够灵活处理,而且内存空间足够,将数据集设置为可迭代对象是明确的选择。app
迭代器:是一个很是节省内存,能够记录取值位置,能够直接经过循环+next方法取值,可是不直观,操做方法比较单一的数据集。函数
应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为何python把文件句柄设置成迭代器)。工具
什么是生成器?这个概念比较模糊,各类文献都有不一样的理解,可是核心基本相同。生成器的本质就是迭代器,在python社区中,大多数时候都把迭代器和生成器是作同一个概念。不是相同么?为何还要建立生成器?生成器和迭代器也有不一样,惟一的不一样就是:迭代器都是Python给你提供的已经写好的工具或者经过数据转化得来的,(好比文件句柄,iter([1,2,3])。生成器是须要咱们本身用python代码构建的工具。最大的区别也就如此了。code
''' 生成器:python社区,生成器和迭代器当作是一种。 区别:生成器是咱们本身用python代码构建的数据和工具。 迭代器都是提供的,或者转化得来的。迭代器都是Python给你提供的已经写好的工具或者经过数据转化得来的。 获取生成器的三种方式: 1.生成器函数(本身写的) 2.生成器表达式(本身写的) 3.python内部提供的一些内置函数,获得的值就是一个生成器 获取迭代器的方式: 1.python提供的,文件句柄 2.经过可迭代对象转换的,-iter()方法 3.python内部提供的一些内置函数,获得的值就是一个迭代器 '''
咱们先来研究经过生成器函数构建生成器。对象
1.yield的用法索引
首先,咱们先看一个很简单的函数:ip
def func(): print(11) return 22 ret = func() print(ret) # 运行结果: # 11 # 22
将函数中的return换成yield,这样func就不是函数了,而是一个生成器函数
def func(): print(11) yield 22
咱们这样写没有任何的变化,这是为何呢? 咱们来看看函数名加括号获取到的是什么?
def func(): print(11) yield 22 ret = func() print(ret) # 运行结果: <generator object func at 0x000001A575163888>
运行的结果和最上面的不同,为何呢?? 因为函数中存在yield,那么这个函数就是一个生成器函数.
咱们在执行这个函数的时候.就再也不是函数的执行了.而是获取这个生成器对象,那么生成器对象如何取值呢?
以前咱们说了,生成器的本质就是迭代器.迭代器如何取值,生成器就如何取值。因此咱们能够直接执行next()来执行如下生成器
def func(): print("111") yield 222 gener = func() # 这个时候函数不会执⾏. ⽽是获取到⽣成器 ret = gener.__next__() # 这个时候函数才会执⾏ print(ret) # 而且yield会将func生产出来的数据 222 给了 ret。 # 结果: # 111 # 222
而且个人生成器函数中能够写多个yield。
def func(): print("111") yield 222 print("333") yield 444 gener = func() ret = gener.__next__() print(ret) ret2 = gener.__next__() print(ret2) ret3 = gener.__next__() # 最后⼀个yield执⾏完毕. 再次__next__()程序报错 print(ret3) 结果: 111 222 333 444 def eat(): for i in range(1, 10000): yield '包子' + str(i) e = eat() for i in range(200): print(next(e)) for i in range(300): print(next(e))
当程序运行完最后一个yield,那么后面继续运行next()程序会报错,一个yield对应一个next,next超过yield数量,就会报错,与迭代器同样。
yield与return的区别:
return通常在函数中只设置一个,他的做用是终止函数,而且给函数的执行者返回值。
yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。
2.yield from
在python3中提供一种能够直接把可迭代对象中的每个数据做为生成器的结果进行返回
# 对比yield 与 yield from def func(): lst = ['卫龙','老冰棍','北冰洋','牛羊配'] yield lst g = func() print(g) print(next(g)) # 只是返回一个列表 def func(): lst = ['卫龙','老冰棍','北冰洋','牛羊配'] yield from lst g = func() print(g) # 他会将这个可迭代对象(列表)的每一个元素当成迭代器的每一个结果进行返回。 print(next(g)) print(next(g)) print(next(g)) print(next(g)) ''' yield from ['卫龙','老冰棍','北冰洋','牛羊配'] 等同于: yield '卫龙' yield '老冰棍' yield '北冰洋' yield '牛羊配' ''' ''' 输出的结果为: <generator object func at 0x000001A7383760C8> ['卫龙', '老冰棍', '北冰洋', '牛羊配'] <generator object func at 0x000001A7383762C8> 卫龙 老冰棍 北冰洋 牛羊配 '''
有个小坑,yield from 是将列表中的每个元素返回,因此 若是写两个yield from 并不会产生交替的效果
def func(): lst1 = ['卫龙','老冰棍','北冰洋','牛羊配'] lst2 = ['馒头','花卷','豆包','大饼'] yield from lst1 yield from lst2 g = func() for i in g: print(i) ''' 卫龙 老冰棍 北冰洋 牛羊配 馒头 花卷 豆包 大饼 '''
列表推导式
# 列表推导式 # 用一行代码去构建一个比较复杂有规律的列表 # l1 = [] # for i in range(1,11): # l1.append(i) # print(l1) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 列表推导式(循环模式) l1 = [i for i in range(1, 11)] print(l1) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 列表推导式分为两类 # 1.循环模式:[变量(加工后的变量)for 变量 in iterable] # 2.筛选模式:[变量(加工后的变量)for 变量 in iterable if条件] # 循环模式 # l1 = [i for i in range(1,11)] # print(l1) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 将10之内全部整数的平方写入列表。 l1 = [i*i for i in range(1,11)] print(l1) 100之内全部的偶数写入列表. l1 = [i for i in range(2,101,2)] print(l1) 从python1期到python100期写入列表lst lst = [f'python{i}' % i for i in range(1,19)] print(lst) 将这个列表中大于3的元素留下来。 l1 = [4, 3, 2, 6, 5, 5, 7, 8] print([i for i in l1 if i > 3]) 三十之内能够被三整除的数。 multiples = [i for i in range(30) if i % 3 is 0] print(multiples) 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 l = ['wusir', 'laonanhai', 'aa', 'b', 'taibai'] # print([i.upper() for i in l if len(i) > 3]) 找到嵌套列表中名字含有两个‘e’的全部名字(有难度) names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print([name for lst in names for name in lst if name.count('e') >= 2]) # 注意遍历顺序,这是实现的关键 # 列表推导式基本上讲完了,固然今天会作一些有关列表推导式的题,让你们更加深刻的了解。
咱们再来研究经过生成器表达式构建生成器。
生成器表达式和列表推导式的语法上如出一辙,只是把[]换成()就好了。好比将十之内全部数的平方放到一个生成器表达式中。
gen = (i**2 for i in range(10)) print(gen) # 结果: <generator object <genexpr> at 0x0000026046CAEBF8>
生成器表达式也能够进行筛选
# 获取1-100内能被3整除的数 gen = (i for i in range(1,100) if i % 3 == 0) for num in gen: print(num)
生成器表达式和列表推导式的区别:
列表推导式比较耗内存,全部数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。
获得的值不同,列表推导式获得的是一个列表.生成器表达式获取的是一个生成器
列表推导式一目了然,生成器表达式只是一个内存地址。
不管是生成器表达式,仍是列表推导式,他只是Python给你提供了一个相对简单的构造方式,由于使用推导式很是简单,因此大多数都会为之着迷,这个必定要深重,推导式只能构建相对复杂的而且有规律的对象,对于没有什么规律,并且嵌套层数比较多(for循环超过三层)这样就不建议你们用推导式构建。
生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.
字典推导式
根据名字应该也能猜到,推到出来的是字典
lst1 = ['jay','jj','meet'] lst2 = ['周杰伦','林俊杰','郭宝元'] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic)
集合推导式
集合推导式能够帮咱们直接生成一个集合,集合的特色;无序,不重复 因此集合推导式自带去重功能
lst = [1,2,3,-1,-3,-7,9] s = {abs(i) for i in lst} print(s) # {1, 2, 3, 7, 9}