You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python yield生成器内list.copy()为何无法隔离原列表修改?

问题核心原因

两种写法结果不一致的本质是 lst.copy()的执行时机完全不同,和浅拷贝、深拷贝的特性没有关系。


带yield的生成器函数执行逻辑

使用yield定义的函数是生成器函数,调用这类函数时不会立刻执行函数内部的任何代码,只会返回一个处于暂停状态的生成器对象,暂停点在函数的第一行代码之前。
只有当你第一次迭代这个生成器对象时,函数体才会从头开始逐行执行。
对应第一版代码,实际执行顺序是:

  1. 初始化原列表lst = [Name("Tom"), Name("Tommy")]
  2. 调用generator(lst)拿到生成器对象gen,此时函数内的lst.copy()完全没有执行
  3. 执行lst[0] = Name("Andrea"),替换原列表的第一个元素
  4. 进入for name in gen循环,触发生成器执行:此时才运行lst.copy()创建列表副本,副本复制的是已经被修改过的原列表,第一个元素已经是Name("Andrea"),最终输出自然是Andrea和Tommy。

返回生成器表达式版本的执行逻辑

第二版写法里的generator是普通函数,不是生成器函数——因为函数内部没有yield关键字,只是直接返回了一个生成器表达式对象。
调用普通函数时,函数内部的代码会立刻同步执行:

  1. 初始化原列表lst = [Name("Tom"), Name("Tommy")]
  2. 调用generator(lst),函数当场执行lst.copy(),此时原列表还没被修改,创建的副本里存的是最初两个Name对象的引用,生成器表达式绑定的是这个提前创建好的副本
  3. 执行lst[0] = Name("Andrea")修改原列表,这个操作不会影响已经创建好的列表副本
  4. 迭代生成器时,遍历的是提前创建的未被修改的副本,自然输出Tom和Tommy。

补充验证:在第一版yield写法中,拿到生成器后先调用一次next(gen),触发函数内的copy逻辑执行完,再去修改原列表,后续的生成器输出就不会被原列表的修改影响了。

内容的提问来源于stack exchange,提问作者ddejohn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:06:21