Python列表的行为不符合预期

时间:2015-11-12 07:40:38

标签: python list mutable

所以我最近一直在学习列表的可变属性,以及变量如何在Python中运行,以及从我的理解下面的代码应该有效:

def history(function, toAdd):
    global history1
    global history2
    global history3
    global history4
    global history5

    if function == 'add':
        history5 = history4[:]
        history4 = history3[:]
        history3 = history2[:]
        history2 = history1[:]
        history1 = toAdd[:]
    elif function == 'undo':
        toReturn = history1[:]
        history1 = history2[:]
        history2 = history3[:]
        history3 = history4[:]
        history4 = history5[:]
        return(toReturn[:])
    elif function == 'return':
        return(history1[:])

但由于某种原因,我传递给历史的列表,

history('add', lst[:])

仍然链接变量,这意味着当我在lst中更改某些内容时,我也会更改history1。我也尝试使用list()而不是[:]但是产生相同的结果。我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

您缺少的是lst[:]只是一个浅层副本。那个新的清单 返回可以添加和删除元素而不影响原始元素 列表,但列表中包含的引用仍然是共享的。所以修改 一个元素,比如说original_list[1].fooBar(),会影响这两个参考 包含在原始列表和新列表中,因为它们是相同的 参考

您需要查看使用deepcopy()(请参阅copy modules's Python docs) - 但是,随附 它是一组自己的问题(不支持它的对象,复制太多等等)。

在你的情况下,它可能意味着history('add', lst[:])应该是真的 类似于:history('add', copy.deepcopy(lst))

您的示例看起来还有其他一些问题。你可能 不想一直创建副本,而是一旦它进入就创建副本 这段历史,可能再次离开?我不确定我理解 真正的问题,所以这可能是糟糕的建议,但我希望代码更多 像:

def history(function, toAdd):
    global history1
    global history2
    global history3
    global history4
    global history5

    if function == 'add':
        history5 = history4
        history4 = history3
        history3 = history2
        history2 = history1
        history1 = copy.deepcopy(toAdd)
    elif function == 'undo':
        toReturn = history1
        history1 = history2
        history2 = history3
        history3 = history4
        history4 = history5

        # Should history5 still be valid at this point?  Maybe do?
        #    history5 = None

        # There could be several issues here.  Remember, this is a deep copy
        # of a previous object/collection.  If your code is  expecting the
        # original object, you will not have it.
        return toReturn
    elif function == 'return':
        # Is it expected that whomever calls this will receive a copy that
        # they can manipulate?  If so, the deepcopy() here is required.
        return copy.deepcopy(history1)

我在上面留下了一些笔记,我认为你应该关注它 的东西。我还会考虑更多地简化这段代码:

from collections import deque
_history_store = deque(maxlen=5)

def history(function, toAdd):
    global _history_store

    if function == 'add':
        _history_store.append(copy.deepcopy(toAdd))

    elif function == 'undo':
        if _history_store:
            return _history_store.pop()

        # No history to return.
        return None

    elif function == 'return':
        if _history_store:
            return copy.deepcopy(_history_store[-1])

        # No history to return.
        return None

使用双端队列将有助于将大小限制为5个条目,而无需这样做 所有人都在洗牌。