Python可迭代对象、迭代器和生成器
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:1097524789
目录
- Python可迭代对象、迭代器和生成器
- 总览:可迭代对象、迭代器、生成器之间的关系
-
-
- 2.2.1 生成器表达式(元组推导式)
- 2.2.2 带有关键字yield的函数
-
-
- 3.1 给定一个list和一个指定数字,求这个数字在list中的位置
- 3.2 给定两个序列,判定第一个是不是第二个的子序列
- 3.3 计算0-9数字的平方和
- 3.4 web自动化测试pytest框架,测试夹具设置前后置条件
总览:可迭代对象、迭代器、生成器之间的关系
- 可迭代对象: 可以进行for循环的都是可迭代对象,原因是其内部实现了一个
__iter__
方法 - 迭代器 :能够用next()函数,都是迭代器对象,其内部实现了
__iter__
和__next__
方法 - 生成器 :元组推导式和函数里使用yield的函数都是生成器
- 生成器是一种特殊的迭代器,迭代器也是可迭代对象,可迭代对象可通过iter()函数转化为成为迭代器
- 容器(列表,元组,字典,集合)是可迭代对象,可迭代对象调用 iter() 函数,可以得到一个迭代器。迭代器可以通过 next() 函数来得到下一个元素,从而支持遍历。
1.可迭代对象和迭代器
1.1 基础概念
_iter_()
_next_()
1.2 判断
from collections.abc import Iterable, Iterator a = [1, 2, 3] b = iter(a) # 可迭代对象调用内置iter()方法返回一个迭代器 isinstance(a, Iterable) isinstance(b, Iterator) isinstance(b, Iterable)
1.3 for循环本质
调用可迭代对象的 _iter_()
方法,得到该对象对应的迭代器对象,然后无限调用 _next_()
方法,得到对象中的每一个元素,直到Stopiteration异常,代表迭代器中已无下一个元素,for循环自动处理该异常,跳出循环。
# 字典的键,值,键值对都是可迭代对象
for key in {'one':1, 'two':2}: print(key) # 字符串是可迭代对象 for char in "123": print(char) # 打开的text同样是可迭代对象 for line in open("myfile.txt"): print(line, end='')
1.4 不想用for循环迭代了,如何使用迭代器?
- 先调用容器(以字符串为例)的iter()函数
- 再使用 next() 内置函数来调用
__next__()
方法 - 当元素用尽时,
__next__()
将引发 StopIteration 异常
1.5 列表推导式
- 用 []
li = [i for i in range(10)] print(li) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 每个元素在生成后都会存在内存中,如果元素很多,就会占用很大的存储空间
迭代器实现一个列表: [i for i in range(1000)]
,
2. 生成器Generator
2.1 概念
在Python中,我们把一边循环一边计算的机制,称为生成器。生成器也是一种迭代器,但由于它们并没有把所有的值存在内存中,而是在运行时生成值,因此只能迭代一次。
使用生成器,可以写出来更加清晰的代码;合理使用生成器,可以降低内存占用、优化程序结构、提高程序速度。
2.2 如何实现和使用?
2.2.1 生成器表达式 (元组推导式)
- 用 ()
ge = (i for i in range(10)) print(li) # <generator object <genexpr> at 0x7f4f446a21d0> next(ge) # 0
- 生成器表达式可以认为是一种特殊的生成器函数,返回生成器对象,一次只返回一个值
2.2.2 带有关键字yield的函数
- 程序运行到yied这一行的时候,生成器调用next()函数生成一个值,同时暂停程序,直到下次调用next()函数时才激活,从上次离开的位置恢复执行
def reverse(data): for index in range(len(data)): yield data[index] print("大大") # reverse('golf'), 此条语句返回一个生成器对象(也是可迭代对象),for循环实现遍历没毛病 for char in reverse('golf'): print(char) # 输出 g o l f 大大 # 遍历方法2 char = reverse('golf') # 返回一个生成器对象,<generator object reverse at 0x7f71c8124250> print(next(char)) print(next(char)) print(next(char)) print(next(char)) print(next(char)) # 输出 g o l f 大大 --------------------------------------------------------------------------- StopIteration Traceback (most recent call last)
3. 应用举例
3.1 给定一个list和一个指定数字,求这个数字在list中的位置
# 常规for循环遍历
def index_normal(L, target): result = [] for i, num in enumerate(L): if num == target: result.append(i) return result print(index_normal([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2)) # 使用生成器 def index_generator(L, target): for i, num in enumerate(L): if num == target: yield i # index_generator会返回一个生成器对象,需要使用list转换为列表后,才能print输出 print(list(index_generator([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2))) # 输出 [2, 5, 9]
3.2 给定两个序列,判定第一个是不是第二个的子序列
解析:序列就是列表,子序列指的是一个列表的元素在第二个列表中都按顺序出现,但是并不必挨在一起
def is_subsequence(a, b): b = iter(b) # 把列表b转化成一个迭代器 return all(i in b for i in a) # (i for i in a),将列表a初始化为一个生成器,可以遍历对象a # i in b,判断生成器next()函数遍历a的指是否在迭代器b调用next()得到的对象中 # all函数,判断一个迭代器的元素是否全部为True print(is_subsequence([1, 3, 5], [1, 2, 3, 4, 5])) print(is_subsequence([1, 4, 3], [1, 2, 3, 4, 5])) # 输出 True False
3.3 计算0-9数字的平方和
sum(i*i for i in range(10)) # 285
3.4 web自动化测试pytest框架,测试夹具设置前后置条件
@pytest.fixture(scope="class")
def browser(): """启动和关闭浏览器""" # 初始化浏览器 driver = webdriver.Chrome() # 设置隐式等待 driver.implicitly_wait(10) # 浏览器页面最大化 driver.maximize_window() # 返回一个浏览器对象 yield driver driver.quit()