迭代深拷贝是解决爆栈最可靠方式,用显式栈替代递归调用,通过memo缓存防循环引用,逐层展开复制并保持类型、顺序与引用关系。

直接用迭代代替递归是解决深拷贝爆栈最可靠的方式。标准 copy.deepcopy 依赖函数调用栈,深度一超就报 RecursionError;而手动用列表模拟栈,把“压栈/出栈”变成显式操作,完全绕过 Python 的递归限制。
核心思路:用栈存待处理项,逐层展开复制
不调用自身函数,而是维护一个栈(list),每个元素记录三样东西:原始对象、它该放进哪个容器、以什么键或索引放。一边出栈,一边创建新对象、填值、再把子项入栈。
- 遇到基本类型(
int、str、bool、float、None)直接返回副本 - 遇到容器(
dict、list、tuple、set),先新建空结构,再把它的每一项(含 key 和 value)打包成元组,推入栈中等待处理 - 用
memo字典缓存已拷贝对象的id()→ 新对象映射,既防循环引用,也避免重复拷贝同一对象
关键细节:怎么保证类型和结构不丢
内置类型可直接构造:[] 对应 list,{} 对应 dict,() 需用 tuple() 包装(因字面量不可变)。对自定义类,若需支持,得检查是否有 __deepcopy__ 方法并调用它;否则跳过或抛错,不强行 pickle。
- 保持原容器类型:判断
isinstance(obj, list)就建新list,不是统一转成list - 顺序敏感结构(如
dict在 3.7+ 有序):遍历时按原顺序处理 key,不打乱 - 跳过不可拷贝对象(线程锁、文件句柄等):提前用
hasattr(obj, '__dict__')或isinstance(obj, (types.FunctionType, type))过滤
实际代码骨架(精简可运行版)
以下是一个最小可行迭代深拷贝实现,不含异常处理但逻辑完整:
def iterative_deepcopy(obj):
memo = {}
stack = [(obj, None, None)] # (原对象, 父容器, 键/索引)
root = None
<pre class='brush:php;toolbar:false;'>while stack:
item, parent, key_or_idx = stack.pop()
if id(item) in memo:
new_item = memo[id(item)]
elif isinstance(item, (int, str, bool, float, type(None))):
new_item = item
elif isinstance(item, list):
new_item = []
memo[id(item)] = new_item
# 把所有子项反向入栈,保证顺序一致
for i, sub in reversed(list(enumerate(item))):
stack.append((sub, new_item, i))
elif isinstance(item, dict):
new_item = {}
memo[id(item)] = new_item
# 按 key 顺序入栈
for k in reversed(list(item.keys())):
stack.append((item[k], new_item, k))
else:
# 其他类型(tuple、set、自定义类等)可依需扩展
raise TypeError(f"Unsupported type: {type(item)}")
if parent is None:
root = new_item
else:
if isinstance(parent, list):
parent[key_or_idx] = new_item
elif isinstance(parent, dict):
parent[key_or_idx] = new_item
return root什么时候该用这个方案
不是所有场景都需要手写。优先按这个顺序判断:
- 数据纯是 JSON 基元(无函数、无日期、无自定义类)→ 用
json.loads(json.dumps(obj))最快最稳 - 只改某一层嵌套,且结构已知 → 手动重建,比如
{k: v.copy() if isinstance(v, dict) else v for k, v in d.items()} - 必须保类型、结构、引用关系,且嵌套深度可能超 500 层 → 上迭代版,或用成熟库如
copyable、deepcopy-iter - 含 NumPy 数组、Pandas DataFrame → 别用
deepcopy,调各自.copy()方法

















