文章目录
Python 生成器:像做菜一样生成数据
想象一下,你正在准备一顿大餐,你需要做很多道菜。你可以一次性把所有菜都做好,但这样会占用很多时间和空间。或者,你可以使用生成器,就像一个聪明的厨师一样,每道菜都按需制作,这样可以节省时间和空间。
生成器就像一个聪明的厨师
-
你可以定义一个生成器函数,就像告诉厨师每道菜的制作方法。
-
生成器函数使用 yield 关键字来 “上菜”,每次调用 next() 函数时,它就会 “端出一道菜”。
-
生成器会记住它上次做菜做到哪里了,下次会从那里继续做菜。
例子:制作水果沙拉
def fruit_salad():
yield "苹果" # 端出第一道 "菜":苹果
yield "香蕉" # 端出第二道 "菜":香蕉
yield "橘子" # 端出第三道 "菜":橘子
salad = fruit_salad() # 创建一个 "厨师" (生成器)
现在,你可以像品尝每道菜一样,逐个获取水果:
print(next(salad)) # 品尝第一道 "菜":输出 "苹果"
print(next(salad)) # 品尝第二道 "菜":输出 "香蕉"
print(next(salad)) # 品尝第三道 "菜":输出 "橘子"
生成器的优点
-
节省空间: 你不需要一次性将所有 “菜” 做好,只需要 “按需制作”,节省内存空间。
-
灵活方便: 你可以根据需要 “点菜”,随时获取下一道 “菜”。
-
菜谱多样: 你可以使用不同的方式来定义生成器函数,创建各种各样的 “菜肴”。
生成器(Generator)是 Python 中一种特殊的迭代器,它可以用来创建自定义的迭代模式,而无需一次性将所有元素加载到内存中。生成器函数使用 yield
关键字来生成值,而不是 return
关键字。
创建生成器
使用生成器函数:
def my_generator(n):
for i in range(n):
yield i
gen = my_generator(3) # 创建一个生成器对象
使用生成器表达式:
gen = (x**2 for x in range(5)) # 创建一个生成器表达式
使用生成器
# 使用 for 循环
for i in gen:
print(i)
# 使用 next() 函数
print(next(gen))
print(next(gen))
斐波那契数列生成器
斐波那契数列是一个经典的数学序列,其中每个数字都是前两个数字之和。例如:0, 1, 1, 2, 3, 5, 8, 13, …
使用生成器,我们可以轻松地生成斐波那契数列,而无需一次性计算所有数字。
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# 生成前 10 个斐波那契数
fib_generator = fibonacci(10)
for number in fib_generator:
print(number)
代码解释:
yield
关键字在Python中用于定义一个生成器函数。当你调用这个函数时,它不会立即执行,而是返回一个生成器对象。当你从这个生成器对象中请求值时(例如通过next()
函数或在for
循环中),函数会执行,直到遇到yield
语句,然后返回yield
后面的值。
在本例中,yield a
会将当前的a
值返回给fib_generator
。然后,函数会“暂停”,等待下一次请求值。当下一次请求值时,函数会从暂停的地方继续执行,计算下一个斐波那契数,然后再次遇到yield
语句,返回新的a
值。
生成器的特性
-
惰性求值: 生成器只在需要时才生成值,节省内存空间。
-
状态保持: 生成器函数在每次调用
next()
时会从上次停止的地方继续执行。 -
单向迭代: 生成器只能向前迭代,不能回退。
-
可组合性: 生成器可以与其他生成器或迭代器组合使用,创建复杂的迭代模式。
生成器的应用场景
-
遍历大型数据集
-
处理数据流
-
实现自定义迭代模式
-
编写高效的算法
自动化测试中迭代器的应用案例
迭代器在软件测试中发挥着重要作用,特别是在处理数据驱动测试和需要灵活遍历数据结构的场景中。例如:
数据驱动测试 (Data-Driven Testing)
-
场景: 测试用例需要使用不同的输入数据进行重复测试,例如测试一个登录功能,需要使用不同的用户名和密码组合。
-
应用:
- 使用迭代器从数据源(如 CSV 文件、Excel 表格、数据库)中读取测试数据。
- 每次迭代生成一组测试数据,用于执行测试用例。
- 结合测试框架,可以方便地实现参数化测试,提高测试效率。
-
示例:
def read_test_data(filename):
with open(filename, 'r') as f:
for line in f:
username, password = line.strip().split(',')
yield username, password
# 使用迭代器读取测试数据
test_data = read_test_data('test_data.csv')
# 遍历测试数据并执行测试用例
for username, password in test_data:
test_login(username, password)
生成器与迭代器的区别
虽然生成器是一种特殊的迭代器,但它们之间还是存在一些关键区别:
创建方式:
-
迭代器: 通过调用
iter()
函数作用于可迭代对象(如列表、元组、字符串)来创建。 -
生成器: 通过定义一个带有
yield
语句的函数来创建。
代码复杂度:
-
迭代器: 实现迭代器协议需要定义 iter() 和 next() 方法,代码相对复杂。
-
生成器: 只需要使用 yield 语句,代码更加简洁易懂。
适用场景:
-
迭代器: 适用于需要多次遍历相同数据集的场景,或者需要随机访问元素的场景。
-
生成器: 适用于处理大型数据集或无限数据流的场景,或者需要自定义迭代逻辑的场景。
总结:
特性 | 迭代器 | 生成器 |
---|---|---|
创建方式 | iter(iterable) | yield 语句 |
元素生成方式 | 一次性生成 | 惰性求值 |
状态保持 | 有 | 有 |
代码复杂度 | 较高 | 较低 |
适用场景 | 多次遍历、随机访问 | 大型数据集、数据流 |
每篇文章都这么用心,你确定不关注一下我吗 (¬‿¬)