自定义深层复制实现

时间:2015-04-07 21:50:48

标签: python python-3.x recursion copy iterable

我试图复制copy.deepcopy的行为。我有一种方法有一些非常奇怪的行为。

def ReplicateIterable(i):
    try:
        if len(i) > 1:
            return [ReplicateIterable(e) for e in i]
        else:
            return i
    except TypeError:
        return i

这是我的功能。 try块用于捕获非迭代。我得到了一些无限的递归问题,因为字符串是可迭代的,我使用字符作为我的列表的元素,因此它在递归之前检查可迭代长度是否为>1

我在测试用例中得到了这种行为:

>>> State = [['a', 'b', 'b', 'b', 'c', 'c', 'c'], []]
>>> TempState = ReplicateIterable(State)
>>> TempState
[['a', 'b', 'b', 'b', 'c', 'c', 'c'], []]
>>> TempState[0].remove('c')
>>> TempState[1].append('c')
>>> State
[['a', 'b', 'b', 'b', 'c', 'c', 'c'], ['c']]
>>> TempState
[['a', 'b', 'b', 'b', 'c', 'c'], ['c']]

显然,TempState[0] 指向State[0],但TempState[1] > 指向State[1]State[0]操作保持TempState[0].remove('c')不变,但State[1]修改了TempState[1]TempState[1].append('c')

为什么会出现这种情况?我该如何预防?

1 个答案:

答案 0 :(得分:3)

问题在于,ReplicateIterable函数中任何短于两个项目的列表都是特殊的,因此在这些情况下不会创建新对象:

>>> l1 = [[], [0], [1, 2]]
>>> l2 = ReplicateIterable(l1)
>>> [i1 is i2 for i1, i2 in zip(l1, l2)]
[True, True, False]

您在问题中的评论表明这是为了避免使用字符串的递归问题,但这并不是一种合适的方法。相反,特别是特殊情况字符串:

def replicate_iterable(iter):  # note style guide compliance
    """Deep copy the iterable."""
    if isinstance(iter, str):
        return iter
    try:
        return [replicate_iterable(item) for item in iter]
    except TypeError:
        return iter