【问题标题】:Difference between path = path + [node1], path += [node1] and path.append(node1)path = path + [node1], path += [node1] 和 path.append(node1) 的区别
【发布时间】:2017-04-18 03:56:14
【问题描述】:

我正在尝试找出两者之间的区别

  1. 路径 = 路径 + [node1]
  2. 路径 += [node1]
  3. path.append(node1)

我得到了 path = path + [node1] 的正确路径,但不是其他两个。

def find_path(self, node1, node2, path = []):
    """ Finds any path from node1 to node2 which may not be the shortest """

    path = path + [node1]
    if node1 == node2:
        return path
    if node1 not in self._graph:
        return None
    for node in self._graph[node1]:
        if node not in path:
            new_path = self.find_path(node, node2, path)
            if new_path:
                return new_path
    return None

【问题讨论】:

  • 什么是节点?您是否收到错误消息或不正确的结果?
  • 它们只是来自 [('A', 'B'), ('B', 'C'), ('B', 'D' ), ('C', 'D'), ('E', 'F'), ('F', 'C')].

标签: python dictionary graph path set


【解决方案1】:

在使用可变默认参数时,您需要非常小心。请参阅“Least Astonishment” and the Mutable Default Argument

行为差异的原因是

path = path + [node1]

创建一个新列表并将其绑定到名称path。其他 2 个替代方案修改绑定到 path 的现有列表。


正如链接问题所解释的,默认参数是在编译函数定义时创建的,不是在调用函数时创建的。这在递归函数中使用可变默认 arg 时尤其重要,因为这意味着默认 arg 在每个顶级递归调用中不会重置。

如果您不想要使用可变默认参数给您带来的“特殊”行为,您可以执行以下操作:

def find_path(self, node1, node2, path=None):
    if path is None:
        path = []
    # rest of code

如果Nonepath 的有效参数,那么您将需要使用其他一些标记,例如

sentinel = object()
def find_path(self, node1, node2, path=sentinel):
    if path is sentinel:
        path = []
    # rest of code

这是一个简短的演示,说明了可变默认参数的“特殊”行为。可以看到lst 记住了之前的内容。

def test(a, lst=[]):
    lst += [a]
    print(a, lst)

for i in range(5):
    test(i)

输出

0 [0]
1 [0, 1]
2 [0, 1, 2]
3 [0, 1, 2, 3]
4 [0, 1, 2, 3, 4]

相比之下,使用lst = lst + [a],我们创建一个新列表而不是附加到默认列表。

def test(a, lst=[]):
    lst = lst + [a]
    print(a, lst)

for i in range(5):
    test(i)

输出

0 [0]
1 [1]
2 [2]
3 [3]
4 [4]

【讨论】:

  • 这解释得很好,非常感谢!所以那里的路径是本地的,而其他两个的路径是全局的,因为它们会影响之前的递归调用?
  • @SandeepChowdary 这不完全是本地/全球问题。默认列表 arg 的行为类似于函数的静态变量,但我想如果您不了解其他语言的静态变量,这种解释并没有多大帮助。 :) 所以我刚刚添加了两个示例,可以清楚地说明发生了什么。顺便说一句,如果我的回答对您有所帮助,请考虑accepting
  • @SandeepChowdary> 与python一样,如果使用可变对象(例如[])作为默认参数,它会在程序开始时创建一次,然后一遍又一遍地重复使用.因此,后续调用将看到之前对其进行的任何修改。这是一个有争议的设计,因为它与大多数其他语言相反,最终成为 Python 初学者(以及一些更有经验的开发者)经常遇到的陷阱
  • 谢谢你们解释得这么好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-16
  • 2015-11-19
  • 1970-01-01
  • 1970-01-01
  • 2014-09-05
  • 2020-09-19
相关资源
最近更新 更多