Python基础8——迭代器 生成器
1.迭代器
-
定义:帮助程序员逐一获取某种对象中的元素
- 对象:包含str、list、tuple、dict、set等序列,即可迭代对象
- 表象:具有
__next__方法且每次调用都获取可迭代对象中的元素(从前到后逐次获取) - 判别一个对象是迭代器的标准:内部是否有
__next__方法
-
列表转换成迭代器
- 方法1:列表作为参数传给内置函数iter()
- 方法2:列表调用本身的转换方法
__iter__()
v1 = [11, 22, 33, 44] # 列表转换成迭代器 v2 = iter(v1) v3 = v1.__iter__() print(v2, type(v2)) print(v3, type(v3)) # <list_iterator object at 0x14204f040> <class 'list_iterator'> # <list_iterator object at 0x100a9a800> <class 'list_iterator'> -
读取迭代器内容
- 方法:反复调用
__next__()方法,直到报错StopIteration错误,表示已经迭代完毕
result1 = v2.__next__() print(result1) result2 = v2.__next__() print(result2) result3 = v2.__next__() print(result3) result4 = v2.__next__() print(result4) result5 = v2.__next__() print(result5) v1 = (11, 22, 33, 44) # v1 = {'k1': 'v1', 'k2': 'v2'} v1 = "hello world" 均可 v2 = iter(v1) while True: try: val = v2.__next__() print(val) except Exception as e: break - 方法:反复调用
-
for循环隐含步骤
- 1.内部会将列表等可迭代对象转换成迭代器
- 2.内部调用
__next__()反复执行迭代器. - 3.取完不报错
for item in [11, 22, 33]: print(item)
2.可迭代对象
- 判断标准
- 内部具有
__iter__()方法且返回一个迭代器(*) - 可以被for循环
v1 = [11, 22, 33, 44] ret = v1.__iter__() print(ret) - 内部具有
3.生成器【函数的变异】
-
判断标准
- 函数中如果存在yield,该函数就是一个生成器函数,调用生成器函数会返回一个生成器
- 生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值
-
案例分析
- 1.普通函数
def func(): return 123 func() # 执行函数,函数内部代码就会运行,结束后返回123- 2.简单生成器函数【内部是否包含yield】
def func(): print('f1') yield 1 print('f2') yield 2 print('f3') yield 100 print('f4') # 函数的内部代码不会执行,返回一个生成器对象 v1 = func() # 生成器可以被for循环,一旦开始循环,那么函数内部代码就会开始执行 for item in v1: print(item) # f1 第1次循环,执行函数,打印 # 1 然后返回1 # f2 第2次循环,接着上次yield后的位置继续执行,打印 # 2 然后返回2 # f3 第3次循环,接着上次yield后的位置继续执行,打印 # 100 然后返回100 # f4 第4次循环,接着上次yield后的位置继续执行,打印 count = 0 for item in v1: # v1是上一段代码中返回的生成器对象 print(item) count += 1 if count == 2: break # f1 # 1 # f2 # 2 def func(): count = 1 while True: yield count count += 1 val = func() # for item in val: # print(item) # 死循环 def func(): return 1 if 1 != 1: yield 1 yield 9 v = func() print(v, type(v)) # <generator object func at 0x141a36140> <class 'generator'> # 只要函数中有yield就是生成器,不用管yield语句能否执行 def func(): return 1 yield 1 yield 9 v = func() for item in v: print(item) # 没有任何输出 def func(): yield 9 return 111 yield 10 v = func() for item in v: print(item) # 输出9 def func(): count = 1 while True: yield count count += 1 if count == 100: return val = func() for item in val: print(item, " ", end="") # 顺序打印1-99- 3.以读文件模仿读取redis示例
# 代码1 def func(): while True: f = open('./db', mode='r', encoding='utf-8') # 通过网络连接上redis data = f.readline() f.close() # 关闭与redis的连接 yield data # 代码2 实现了按行读取数据,但链接会一直连着占用资源,导致其他人无法连接redis def func(): f = open('./db', mode='r', encoding='utf-8') # 通过网络连接上redis while True: data = f.readline() if not data: break yield data f.close() # 关闭与redis的连接 # 代码3:模仿redis源码实现 def func(): cursor = 0 while True: f = open('./db', mode='r', encoding='utf-8') # 通过网络连接上redis # 代指 redis[0:10] f.seek(cursor) data_list = [] for i in range(10): line = f.readline() if not line: return data_list.append(line) cursor = f.tell() f.close() # 关闭与redis的连接 for row in data_list: yield row for item in func(): print(item) # redis源码示例 def scan_iter( self, match: Union[PatternT, None] = None, count: Union[int, None] = None, _type: Union[str, None] = None, **kwargs, ) -> Iterator: """ Make an iterator using the SCAN command so that the client doesn't need to remember the cursor position. ``match`` allows for filtering the keys by pattern ``count`` provides a hint to Redis about the number of keys to return per batch. ``_type`` filters the returned values by a particular Redis type. Stock Redis instances allow for the following types: HASH, LIST, SET, STREAM, STRING, ZSET Additionally, Redis modules can expose other types as well. """ cursor = "0" while cursor != 0: # 每次去取100个 # cursor是取完之后的游标位置 # data本次取出来100条数据 cursor, data = self.scan( cursor=cursor, match=match, count=count, _type=_type, **kwargs ) yield from data # redis读取数据示例.py import redis conn = redis.Redis(host='192.168.11.11') # scan_iter是一个生成器函数 result = conn.scan_iter(count=100) for item in result: print(item) conn.close()![]()
- 4.带yield from的生成器
def base(): yield 88 yield 99 def func(): yield 1 yield 2 yield from base() # 在函数和函数之间交叉着做生成器 yield 3 result = func() for item in result: print(item) # 1 # 2 # 88 # 99 # 3 def base(): # return 123 执行报错 123不是可迭代对象 return [11, 22] # 将列表拆分返回 def func(): yield 1 yield 2 yield from base() yield 3 result = func() for item in result: print(item) # 1 # 2 # 11 # 22 # 3 def base(): return [11, 22] # 将列表整体返回,意义不大 def func(): yield 1 yield 2 yield base() yield 3 result = func() for item in result: print(item) # 1 # 2 # [11, 22] # 3- 5.生成器推导式
- 面试题:请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别?
- 前者直接生成列表,后者是一个生成器(注意后者不是集合)
- 面试题:请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别?
// 1.复习列表推导式 # def func(): # result = [] # for i in range(10): # result.append(i) # return result # v1 = func() v1 = [i for i in range(10)] # 列表推导式,立即循环创建所有元素 print(v1) v1 = [lambda :i for i in range(10)] for item in v1: print(item(), ' ', end="") # 9 9 9 9 9 9 9 9 9 9 def func(): result = [] for i in range(10): def f(): return i result.append(f) return result v1 = func() for item in v1: print(item(), ' ', end="") # 9 9 9 9 9 9 9 9 9 9 // 2.生成器推导式案例 # def func(): # for i in range(10): # yield i v2 = (i for i in range(10)) # 生成器推导式,创建了一个生成器,内部循环未执行 print(v2) for item in v2: print(item, ' ', end="") # <generator object <genexpr> at 0x13a101840> # 0 1 2 3 4 5 6 7 8 9 def func(): for i in range(10): def f(): return i yield f v1 = func() for item in v1: print(item(), ' ', end="") # 0 1 2 3 4 5 6 7 8 9 v1 = (lambda :i for i in range(10)) for item in v1: print(item(), ' ', end="") # 0 1 2 3 4 5 6 7 8 9
4.小结
- 迭代器
- 对可迭代对象中的元素进行逐一获取,迭代器内部都有一个
__next__()方法,用于逐个获取数据
- 对可迭代对象中的元素进行逐一获取,迭代器内部都有一个
- 可迭代对象
- 可以被for循环
- 此类对象中有
__iter__()方法且要返回一个迭代器或生成器
- 生成器
- 函数内部有yield则就是生成器函数,调用函数则返回一个生成器,循环生成器时则函数内部代码才会执行
- 是一种特殊的迭代器,也是一种特殊的可迭代对象
def func(): yield 1 v = func() print(v, type(v)) for i in dir(v): print(i) # 查看v中都有哪些方法 出现了__iter__() 和 __next__() def func(): yield 1 v = func() ret = v.__iter__() print(ret) # <generator object func at 0x134b4c510> class Foo(object): pass # 创建类的对象 obj = Foo() # 不能被循环,不是可迭代对象 for item in obj: print(item) # 报错TypeError: 'Foo' object is not iterable class Foo(object): def __iter__(self): return iter([11, 22, 33]) # 创建类的可迭代对象 obj = Foo() # 可以被for循环 for item in obj: print(item) # 11 22 33 class Foo(object): def __iter__(self): yield 1 yield 2 yield 3 # 创建类的可迭代对象 obj = Foo() # 可以被for循环 for item in obj: print(item) # 1 2 3


浙公网安备 33010602011771号