Python函数内操作列表副本仍修改原列表的问题求助
问题描述
我编写了两个函数:
recursiveScanText:在对象数组中查找y0值匹配的元素,返回对应文本字符串mergeSimilarText:合并y坐标相近(±5)的对象
我已经在mergeSimilarText中对输入列表执行了copy()操作,但运行代码后原输入列表tmp仍被修改。我定位到问题出在第26行修改BOLD_OBJ["text"]的操作,但不清楚原因。之前误以为这是字典数组而非数组数组,无需使用深拷贝,尝试修改拷贝方式也没解决问题。
原代码
def recursiveScanText(BOLD_OBJ_LIST:list, Y_VALUE: int, output: list): if BOLD_OBJ_LIST[0]["y0"] == Y_VALUE: output.append(BOLD_OBJ_LIST[0]["text"]) BOLD_OBJ_LIST.pop(0) if BOLD_OBJ_LIST == []: return output output = recursiveScanText(BOLD_OBJ_LIST, Y_VALUE, output) return output else: return output def mergeSimilarText(BOLD_OBJ_LIST: list): """Merges the objects of a list of objects if they are at a similar (±5) Y coordinate""" OUTPUT = [] RECURSIVE_SCAN_OUTPUT = [] BOLD_OBJ_LIST = BOLD_OBJ_LIST.copy() for BOLD_OBJ_INDEX in range(len(BOLD_OBJ_LIST)): if len(BOLD_OBJ_LIST) > 0 and BOLD_OBJ_INDEX < len(BOLD_OBJ_LIST): BOLD_OBJ = BOLD_OBJ_LIST[0] BOLD_CHAR_STRING = recursiveScanText(BOLD_OBJ_LIST, BOLD_OBJ_LIST[BOLD_OBJ_INDEX]["y0"], RECURSIVE_SCAN_OUTPUT) RECURSIVE_SCAN_OUTPUT = [] BOLD_OBJ["text"] = "".join(BOLD_CHAR_STRING) OUTPUT.append(BOLD_OBJ) return OUTPUT tmp = [ {'y0': 762.064, 'text': '177'}, {'y0': 762.064, 'text': '7'}, {'y0': 114.8281, 'text': 'Q'}, {'y0': 114.8281, 'text': 'u'}, {'y0': 114.8281, 'text': 'e'}, {'y0': 114.8281, 'text': 's'}, {'y0': 114.8281, 'text': 't'}, {'y0': 114.8281, 'text': 'i'}, {'y0': 114.8281, 'text': 'o'}, {'y0': 114.8281, 'text': 'n'}, {'y0': 114.8281, 'text': ' '}, {'y0': 114.8281, 'text': '1'}, {'y0': 114.8281, 'text': '7'}, {'y0': 114.8281, 'text': ' '}, {'y0': 114.8281, 'text': 'c'}, {'y0': 114.8281, 'text': 'o'}, {'y0': 114.8281, 'text': 'n'}, {'y0': 114.8281, 'text': 't'}, {'y0': 114.8281, 'text': 'i'}, {'y0': 114.8281, 'text': 'n'}, {'y0': 114.8281, 'text': 'u'}, {'y0': 114.8281, 'text': 'e'}, {'y0': 114.8281, 'text': 's'}, {'y0': 114.8281, 'text': ' '}, {'y0': 114.8281, 'text': 'o'}, {'y0': 114.8281, 'text': 'n'}, {'y0': 114.8281, 'text': ' '}, {'y0': 114.8281, 'text': 'p'}, {'y0': 114.8281, 'text': 'a'}, {'y0': 114.8281, 'text': 'g'}, {'y0': 114.8281, 'text': 'e'}, {'y0': 114.8281, 'text': ' '}, {'y0': 114.8281,'text': '9'}] print(mergeSimilarText(tmp)) print(tmp)
问题原因
- 列表浅拷贝的局限性:
BOLD_OBJ_LIST.copy()是浅拷贝,它只复制了列表本身的结构,但列表中的每个字典元素还是和原列表tmp里的字典指向同一个内存地址。也就是说,新列表和原列表共享里面的字典对象。 - 字典修改的直接影响:当你执行
BOLD_OBJ["text"] = "".join(BOLD_CHAR_STRING)时,本质是在修改共享的字典对象内容,自然会同步反映到原列表tmp中对应的元素上。
解决方法
提供两种可行的解决方案:
方案1:使用深拷贝
通过copy.deepcopy()创建完全独立的列表,里面的每个字典都会被完整复制,修改新列表中的字典不会影响原列表。
修改后的mergeSimilarText函数:
import copy def mergeSimilarText(BOLD_OBJ_LIST: list): """Merges the objects of a list of objects if they are at a similar (±5) Y coordinate""" OUTPUT = [] RECURSIVE_SCAN_OUTPUT = [] # 替换为深拷贝 BOLD_OBJ_LIST = copy.deepcopy(BOLD_OBJ_LIST) for BOLD_OBJ_INDEX in range(len(BOLD_OBJ_LIST)): if len(BOLD_OBJ_LIST) > 0 and BOLD_OBJ_INDEX < len(BOLD_OBJ_LIST): BOLD_OBJ = BOLD_OBJ_LIST[0] BOLD_CHAR_STRING = recursiveScanText(BOLD_OBJ_LIST, BOLD_OBJ_LIST[BOLD_OBJ_INDEX]["y0"], RECURSIVE_SCAN_OUTPUT) RECURSIVE_SCAN_OUTPUT = [] BOLD_OBJ["text"] = "".join(BOLD_CHAR_STRING) OUTPUT.append(BOLD_OBJ) return OUTPUT
方案2:创建新字典再修改
不直接修改原字典引用,而是复制字典内容生成新对象,再修改text字段,避免影响原列表中的字典。
修改mergeSimilarText中修改text的部分:
# 替换原BOLD_OBJ["text"]修改和OUTPUT.append的代码 new_obj = BOLD_OBJ.copy() # 复制原字典生成新对象 new_obj["text"] = "".join(BOLD_CHAR_STRING) OUTPUT.append(new_obj)
额外优化提示
原recursiveScanText函数的逻辑存在冗余,且mergeSimilarText中的循环在执行pop(0)后会出现索引错位问题,可以考虑用迭代方式替代递归,同时优化循环逻辑,避免不必要的索引判断。
内容的提问来源于stack exchange,提问作者Toby Clark
相关产品推荐
相关产品推荐

