一、迭代器
- 1.list、str、tuple、dict等数据类型,可以使用
for...in...
循环语句进行遍历,并依次返回数据。这样的我们称它是可迭代对象。 - 2.可迭代对象的本质:
- 1.当我们使用for…in… 进行每一次迭代时,都会依次返回一个数据直至没有数据,结束。那在这个过程中,会有这么一个“人”去给我们记录这次获取哪个数据,下次又要获取哪个数据,那这个帮我们记录数据的“人”,称为迭代器。
- 2.iter(): 可迭代对象是通过
__iter__
方法向我们提供一个迭代器,也就是指向提供的那个迭代器。当我们遍历时,我们是通过 iter() 函数 获取该可迭代对象里的迭代器,然后对这个迭代器不断使用 next() 方法,进行返回数据。【注:当我们迭代完最后一个数据之后,再次调用next() 会抛出StopIteration的异常,来告诉我们已经没有数据了,不需要再使用 next() 函数】 - 3.next(): 看上面所说的,那是不是定义一个 **next()**方法 的就是迭代器了?答案是否的,因为在Python中要求,迭代器本身也是可迭代的,所以还要在迭代器中实现
__iter__
方法。迭代器里面定义__iter__
方法,难道又要提供一个新的迭代器?不是的,我们知道它本身就是一个迭代器,所以在__iter__
方法中,只要返回自身就好了。
【总结】
- 1.实现了iter方法的对象一定是可迭代对象,但不一定是一个迭代器。
- 2.同时实现了iter方法跟next方法的对象,就一定是一个迭代器。
- 3.看下面的代码,大致的执行流程就是,我们调用一个自定义的可迭代对象MyList(),通过
__iter__
方法获取一个MyIterator()迭代器,再通过迭代器下的__next__
方法,返回数据。 - 4.所以说 for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
from collections import Iterable, Iterator
# 自定义的一个可迭代对象
class MyList(object):
def __init__(self):
self.items = [] # 最后添加完数据的列表为:[1, 2, 3, 4, 5]
def add(self, val):
self.items.append(val)
def __iter__(self):
myiterator = MyIterator(self)
return myiterator
# 自定义的供上面可迭代对象使用的一个迭代器
class MyIterator(object):
def __init__(self, mylist):
self.mylist = mylist
# current用来记录当前访问到的位置,也就是索引
self.current = 0
def __next__(self):
# 获取可迭代对象的长度
if self.current < len(self.mylist.items):
item = self.mylist.items[self.current]
self.current += 1
return item
else:
raise StopIteration
def __iter__(self):
return self
if __name__ == '__main__':
mylist = MyList()
# 先添加数据
mylist.add(1)
mylist.add(2)
mylist.add(3)
mylist.add(4)
mylist.add(5)
# 先通过 __iter__ 获取一个迭代器
ret = mylist.__iter__()
# 再通过迭代器中的 __next__() 拿到每一个数据;
# 直到报:StopIteration 错误,停止 __next__。
while True:
try:
print(ret.__next__())
except StopIteration:
print('已遍历完毕!')
break
# 这也就是for循环大致的实现过程
# for num in mylist:
# print(num)
x = isinstance(mylist, Iterable) # 判断该对象是否是可迭代对象,是:True;否:False
y = isinstance(ret, Iterator) # 判断该对象是否是迭代器,是:True;否:False
print('是否是可迭代对象:', x, '\n是否是迭代器:', y)
【扩展】
-
1.
dir()
:dir(数据),返回该数据可以执行的所有操作。 -
2.导入:
from collections import Iterable, Iterator
isinstance(对象, Iterable) # 判断该对象是否是可迭代对象,是:True;否:False
isinstance(对象, Iterator) # 判断该对象是否是迭代器,是:True;否:False
二、生成器
-
其生成器的本质就是一个
迭代器
。 -
创建一个生成器:
-
第一种,通过生成器表达式来获取生成器
( x for x in range(5)) # 注意;误区:没有元组推导式,这叫生成器表达式
-
第二种,生成器函数
# 只要在函数中,存在yield,那么该函数就是一个生成器函数; # 注意,生成器函数运行之后,产生一个生成器,而不是运行该函数 def function(): print('这是一个生成器函数') yield '没错,答对咯!' # yield 表示返回和return的作用差不多 # 但不会向return那样返回时,终止函数的执行,而是可以分段的执行一个函数 print('打印我,打印我~') val = yield '不要着急,一个一个来~' # 注意,这里val如果没有被传值时,val是等于None; # 因为yield 会将'不要着急,一个一个来~'进行返回,此时,val的值就为None,而不是'不要着急,一个一个来~'。 print(f'来点不一样的...val + 1 = {val + 1}') yield '结束《《' # 注意,此时并没有运行函数 gen = function() print(gen) # 它是一个生成器 ret1 = gen.__next__() # 第一次执行 __next__ ,此时才开始运行该函数 print(ret1) # 注意,该返回值是 yield 返回的值 ret2 = gen.__next__() # 第二次执行 __next__, 将会接着上一次yeild的位置,进行往下运行。 print(ret2) # send() : 可以给上一个yield的位置,进行传值。 ret3 = gen.send(5) print(ret3)
# 传统的使用return,将会一次性返回结果集,可能我们一时不需要这么多结果,这样就会浪费内存 def function(): lst = [] for i in range(1, 1001): lst.append(i) return lst gen = function() print(gen) # 可以看出,同样的1000个量,此时,我们需要多少量,就拿多少量,这样就不会造成浪费内存了; # 总结:生成器、迭代器 最大的优点:节省内存空间 def function1(): for i in range(1, 1001): yield i gen1 = function1() print(gen1) print(gen1.__next__()) print(gen1.__next__()) print(gen1.__next__()) print(gen1.__next__())
-
第三种,类型转换
🔨正在努力编辑中…
-
-
总结:
- 所有的生成器都是迭代器
- 可以使用
list()
方法获取到生成器中的所有数据 - 优点:节省内存空间;特点:惰性机制,只能向前,不能反复。
新手上路,代码写的不好,还请谅解,如果有理解错误的,也请大佬在评论区指出来,非常感谢!
以上就是迭代器、生成器的所有内容了,点赞收藏加评论是最大的支持哦!
📑编写不易,转载请注明出处,如有侵权,请联系我!