生成器案例

生成器案例

【一】源码

def add(n, i):
    return n + i


def test():
    for i in range(4):
        yield i


g = test()
for n in [1, 10, 11]:
    g = (add(n, i) for i in g)
    
res = list(g)
print(res)
  • 待选项
# A. res=[10,11,12,13]
# B. res=[11,12,13,14]
# C. res=[20,21,22,23]
# D. res=[21,22,23,24]

【二】解析

【1】源码解析

# 定义一个函数add,接受两个参数n和i,返回n加i后的结果 
def add(n, i):
    return n + i

# 定义一个生成器函数test,使用for循环生成0至3的整数序列
def test():
    for i in range(4):
        yield i

# 调用test函数,并将生成器赋值给g
g = test()

# 对列表[1, 10, 11]进行迭代
for n in [1, 10, 11]:
    # 使用生成表达式生成新的生成器对象
    g = (add(n, i) for i in g)

"""
根据迭代到的值进行三次循环,每次生成一个新的生成器
第一次循环 g = (add(1, i) for i in g)
第二次循环 g = (add(n, i) for i in (add(n, i) for i in g))
第三次循环 g = (add(n, i) for i in (add(n, i) for i in (add(n, i) for i in g)))
"""

# 将生成器g转换为列表并打印结果
res = list(g)
print(res)

【2】思路解析

  • 这段代码使用了生成器和生成表达式。
    • 首先,test()函数是一个生成器函数,它会生成0到3的整数序列。
    • 当test()被调用时,它不会立即生成整个序列,而是每次生成一项。
  • 因此,在g=test()后,g只是一个生成器对象,它还没有生成任何一项。
  • 在下面的代码中,add(n,i)for i in g是一个生成表达式,它会从g中取出每个元素,并将其传递给add(n,i)。
  • 代码中的循环会三次遍历[1, 10, 11]中的每个元素,并在每次遍历中生成一个新的生成器对象。
    • 第一次循环时,g是(add(1,i)for i in g)。
      • 这意味着,对于test提供的输入,add(1,i)会作用于每个整数。
      • 因此,第一次循环后,g是[1, 2, 3, 4]。
    • 在第二次循环中,g被初始化为(add(n,i)for i in g)。
      • 这将进入一个嵌套的循环,即运行内层循环以生成新值的循环和运行外层循环以产生输出的循环。
      • 后面的括号包含内部循环,它是由前一个循环生成的生成器组成的。
      • 因此,第二次循环后,g是[11, 12, 13, 14]。
    • 第三次循环以相同的方式工作,但在此之后不再生成组,
      • 因此结果是[21, 22, 23, 24]。
  • 所以,正确答案是D,即res=[21, 22, 23, 24]。

【三】注解

# 定义一个函数add,接受两个参数n和i,返回n加i后的结果
def add(n, i):
    return n + i


# 定义一个生成器函数test,使用for循环生成0至3的整数序列
def test():
    for i in range(4):
        yield i


# 调用test函数,并将生成器赋值给g
g = test()

# 对列表[1, 10, 11]进行迭代
for n in [1, 10]:
    # 使用生成表达式生成新的生成器对象
    g = (add(n, i) for i in g)

"""
根据迭代到的值进行三次循环,每次生成一个新的生成器
第一次循环 g = (add(1, i) for i in g)
第二次循环 g = (add(n, i) for i in (add(n, i) for i in g))
"""

# 将生成器g转换为列表并打印结果
res = list(g)
print(res)
# [20, 21, 22, 23]
在第一次循环中,由于g已经是从test()中生成的整数序列,所以g通过(add(1, i) for i in g)生成了一个新的生成器对象,该生成器对象是通过将每个i值与1相加得到的:(add(1, 0), add(1, 1), add(1, 2), add(1, 3)),记为g1。 

所以当第二次循环时,由于n是10,我们需要修改g1而不是之前的g。

因此,g不再是来自test()中的整数序列,而是从上一次循环中的g1产生的。

因此,直接使用(add(n, i) for i in g)无法得到正确的答案。

我们需要先对g1中的每个元素加10,然后再将结果传递给add函数。

这是通过将g1放入括号中,并创建另一个生成器来执行的(add(n, i) for i in (add(n, i) for i in g1))。

这样就将每个i值与10相加两次,等价于add(10, add(1, 0)), add(10, add(1, 1)), add(10, add(1, 2)), add(10, add(1, 3)),记为g2。

因此,第二次循环后,g变成了g2。

在第三次循环中,因为需要将g2中的每个元素都加10次,所以在(add(n, i) for i in (add(n, i) for i in g2))中,需要添加更多嵌套,以便将每个i与n相加多次。

因此,在每次循环时,都将g传递给新的生成器,每个新的生成器都会执行add(n, i)函数,并生成一个新的生成器。

由于在第一次迭代中n为1,因此第一次迭代的结果是(add(1, i) for i in g)。

在第二次迭代中,由于n为10,我们必须在上一个生成器中的所有值上调用add(10, i)。

因此,需要用新的生成器重新包含上一个生成器的返回值,并传递给add(n, i)。当它们的值传递给函数后,我们可以获得最终列表[20, 21, 22, 23]。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值