【问题标题】:Difference between creating a new list an mutating an existing one创建新列表与改变现有列表之间的区别
【发布时间】:2016-03-09 23:46:23
【问题描述】:

我正在尝试计算图中从节点start 到另一个end 的最短路径。我一直在阅读 + 运算符应用于列表,将元素连接到前者的末尾,结果创建了一个新列表。而使用.extend() 不仅可以将元素添加到列表的末尾,还可以保持相同的列表实例。

我不明白为什么如果我使用path = path + [start] 我的代码可以工作,而不是如果我使用path.extend(start)。我不认为每次调用函数时都需要创建一个新列表来返回正确的结果。

def shortest_path_edge_num(graph, start, end, path = None, shortest = None):
    if (graph or start or end) is None: return None
    if path is None: path = []
    if shortest is None: 
        shortest = []

    path = path + [start]
    # path.extend([start])
    # Base case:
    if start == end: return path

    for adj_node in graph[start]:
        if adj_node[0] not in path:
        new_path = shortest_path_edge_num(graph, adj_node[0], end, path, shortest)
            if new_path:
                if (not shortest) or (len(new_path) < len(shortest)):
                    shortest = new_path
    return shortest

# Main routine
graph = {
    'A' : [('B',5),('F',10)],
    'B' : [('A',5),('E',2),('C',4)],
    'C' : [('B',4),('D',11)],
    'D' : [('C',11),('E',7)],
    'E' : [('B',2),('D',7),('F',1)],
    'F' : [('A',10),('E',1)]
}

print shortest_path_edge_num(graph,'A','C')

>>> python graph.py
['A', 'B', 'C']
>>> # But when changing to path.extend([start])
>>> python graph.py
['A', 'B', 'E', 'D', 'C', 'F']

编辑

使用+ 会创建list 的新实例,因此在我每次向path 添加新元素时,以某种方式依赖它的所有其他变量都不会改变。现在的问题应该是我应该如何消除这种依赖?

【问题讨论】:

  • 你的意思是,你使用了 path.extend([start])?因为 extend() 仅适用于 2 个列表。还是您使用 path.append(start) ?
  • 我拼错了.extend()。刚刚更正了。

标签: python graph shortest-path


【解决方案1】:

path.extend() 期望另一个序列作为其参数。和你说的path + [start]一样,你需要说path.extend([start])。然而,更简单的方法是使用.append():path.append(start)Herelist 上的文档。

【讨论】:

  • 我的第一种方法是使用path.append(start),但由于它不起作用,实际上path.extend([start]) 也不起作用,我尝试使用+
  • 是的,这是我让它工作的唯一方法,但我不明白为什么会这样。
  • path.append(start)path.extend([start]) 等效于 path = path + [start](除了它会影响引用同一列表的其他变量)。
  • 不同之处在于,如果我使用.append() 并分配给new_path,则使用path 的函数的结果每个path.append(...) 将修改以某种方式依赖的所有其他列表path 的实例。这就是为什么它只适用于+
  • 好的。顺便说一句,如果您想使用path += [start] 来缩短它,请不要。那是path.__iadd__([start]) 的快捷方式,所以它仍然会修改所有其他的。
【解决方案2】:

我不知道对path 应用操作会导致修改其他变量,例如new_pathshortest。当我看到做path.append(start)path.extend([start]) 也将start 添加到其他两个列表时,我意识到在new_path = shortest_path_edge_num(graph, adj_node[0], end, path, shortest) 中递归调用函数时我不应该使用path,而是使用path[:] 以便发送列表的副本,而不是参考。

所以最后我保留了path.append(start)path.extend([start])这一行,并在递归调用中修改了参数path[:]。通过这样做,程序按预期返回了最短路径。

感谢 cmets 和答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-12
    • 2022-01-01
    • 2018-09-24
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    相关资源
    最近更新 更多