传递给函数时链接列表的确如何表现?

时间:2018-03-05 15:34:42

标签: python-3.x linked-list

这是我的Node类:

class Node:

 def __init__(self, value):
   self.value = value
   self.next = None

 def __repr__(self):
   if self.next == None:
     return 'Node({})'.format(repr(self.value))
   else:
     return 'Node({}, {})'.format(
       repr(self.value), repr(self.next))

这是我的方法m:

def m(lnk):
   while lnk and lnk.next:
       lnk.next = lnk.next.next
       lnk = lnk.next
   print(lnk)

然后我运行以下代码:

lnk = Node(1)
lnk.next = Node(2)
lnk.next.next = Node(3)
m(lnk)
print(lnk)

第一个输出是Node(3),第二个输出是Node(1,Node(3))。我理解第一个输出,但它是我不能得到的第二个输出。为什么Node(1)仍在那里?我认为lnk将作为参考传入,因此会改变并具有与我的函数中相同的值。但是,这种情况并没有发生,我也不明白为什么。

2 个答案:

答案 0 :(得分:2)

你现在的问题是你的m函数没有做到它应该做的事情。通过删除第lnk.next = lnk.next.next行来更改它:

def m(lnk):
   while lnk and lnk.next:
       lnk = lnk.next
   print(lnk)

然后,您将获得以下结果:

>>> m(lnk)
Node(3)
>>> print(lnk)
Node(1, Node(2, Node(3)))

那么,什么在做什么?

__repr__说如果你是列表的最后一部分,则返回“Node(#)”,其中#是值。如果您不是列表的最后一部分,请返回您下方的节点列表。

修改后的m函数现在只需打印列表中的最后一个节点。

详细了解您当前的设置以及m功能的作用:

当前:lnk = {'value':1,'next':{'value':2,'next':{'value':3,'next':无}}}

循环通过m的第一遍获取您传入的对象,称为lnk,其定义如上,并将其更改为lnk = {'value':1,'next ':{'value':3,'next':无}}(因为lnk.next = lnk.next.next)。在循环中的第二次传递中,lnk变量已更改。它不再指向同一个对象;它指向对象{'value':3,'next':None},循环停止,因为'next'是None。

请注意,这修改了您的链接列表,我认为这不是意图。

Evan指出你的参考是一个很好的参考。在阅读有关内容时,您会看到函数内的变量名是本地的。它首先引用您创建的Node(1)对象,但是当您将其分配给其他对象时,它不再引用该对象。但是,它不是通过值传递的,因为您在该对象内部进行的更改(例如设置lnk.next.next)仍然存在。

创建初始链表时,需要使用.next.next语法来避免为每个节点创建临时变量。您也可以像这样构建列表:

node1 = Node(1)
node2 = Node(2)
node3 = Node(3)

node1.next = node2
node2.next = node3
linked_list = node1

现在,如果要更新lnk以指向列表的尾部,则需要返回本地变量。 m及其用法应该是这样的:

def m(node):
    while node and node.next:
        node = node.next
    return node

tail = m(lnk)

请注意,我将m的参数重命名为node。这可以帮助您避免混淆lnk的设置或修改位置。如果您继续修改列表,请意识到您的结果仍然相同。即使它的名称为node,行node.next = node.next.next仍然会在较高的范围内修改名为lnk的变量。

在样式注释中,我强烈建议不要命名函数m。给它一个名称,如get_tailget_leaf,这样就可以清楚它的功能。至少你的一些困惑来自于没有明确定义m应该做什么。

如果你必须修改函数内部的lnk变量(变量本身,而不是内容),你可以使用全局变量来做,但这几乎总是一个坏主意,不应该这样做。 (因为人们习惯于变量的行为,并且改变行为会使代码更难维护。在这种情况下,大多数人都希望链接列表上的操作不具有破坏性,除非它在语义上明显是他们想要的,例如pop。)

def m():
    global lnk
    while lnk and lnk.next:
        lnk = lnk.next

答案 1 :(得分:1)

Variables in Python are not passed by reference, but by assignment.它实际上与在C或C ++中传递指针变量相同:如果更改函数内可变对象的字段,则更改将在调用范围中可见,但如果您改变变量本身的身份,它不会。