为什么不会永久覆盖此Python对象属性?

时间:2017-07-09 02:09:45

标签: python algorithm object scope linked-list

我正在使用Python处理链接列表分区问题。目标是将链表分成2个段,第一个值小于x,第二个值等于或大于x。

我对分区函数的第一行感到困惑:

current = ll.tail = ll.head

为什么此行永久不会覆盖ll.tail的值?我认为Python是一种通过引用传递对象的语言。 llll.headll.tail都是对象,因此我的期望是此行会导致使用丢失ll.tail中存储的值。

ll.tail存储函数输出所需的值,它仍然存在于函数的输出中(并且输出正确),但我不明白如何。

Partition.py:

from LinkedList import LinkedList


def partition(ll, x):
    current = ll.tail = ll.head

    while current:
        nextNode = current.next
        current.next = None
        if current.value < x:
            current.next = ll.head
            ll.head = current
        else:
            ll.tail.next = current
            ll.tail = current
        current = nextNode

    # Error check in case all nodes are less than x
    if ll.tail.next is not None:
        ll.tail.next = None


ll = LinkedList()
ll.generate(10, 0, 99)
print(ll)
partition(ll, ll.head.value)
print(ll)

LinkedList.py:

from random import randint


class LinkedListNode:

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

    def __str__(self):
        return str(self.value)


class LinkedList:

    def __init__(self, values=None):
        self.head = None
        self.tail = None
        if values is not None:
            self.add_multiple(values)

    def __iter__(self):
        current = self.head
        while current:
            yield current
            current = current.next

    def __str__(self):
        values = [str(x) for x in self]
        return ' -> '.join(values)

    def __len__(self):
        result = 0
        node = self.head
        while node:
            result += 1
            node = node.next
        return result

    def add(self, value):
        if self.head is None:
            self.tail = self.head = LinkedListNode(value)
        else:
            self.tail.next = LinkedListNode(value)
            self.tail = self.tail.next
        return self.tail

    def add_to_beginning(self, value):
        if self.head is None:
            self.tail = self.head = LinkedListNode(value)
        else:
            self.head = LinkedListNode(value, self.head)
        return self.head

    def add_multiple(self, values):
        for v in values:
            self.add(v)

    def generate(self, n, min_value, max_value):
        self.head = self.tail = None
        for i in range(n):
            self.add(randint(min_value, max_value))
        return self

1 个答案:

答案 0 :(得分:1)

您认为有问题的行不是您的问题。此代码说明了原因:

def checker(ll):
    current = ll.tail = ll.head
    print(current)
    print(ll.tail)
    print(ll.head)
    return
ll = LinkedList()
ll.generate(10,0,99)
print(ll)
checker(ll)
print(ll.tail) 
print(ll.head)
print("Some other interesting behavior:")
ll.head.value = -1
print(ll.head)
print(ll.tail)
ll.head = -2
print(ll.head)
print(ll.tail)

使用您自己的LL代码给出:

73 -> 39 -> 14 -> 5 -> 47 -> 29 -> 14 -> 66 -> 70 -> 9
73
73
73
73
73
Some other interesting behavior:
-1
-1
-2
-1

因此,在函数中修改时,传递的链接列表会发生更改。还要注意最后的行为:ll.tail现在指向ll.head指向的位置,而不是ll.head本身。这与C的指针引用不同。

这意味着您的算法没有按预期执行。特别是我会关注循环何时结束以及交换它的顺序(通常是LL活动的大多数错误似乎发生的地方)。

一般调试技术,如单元测试潜在功能(或预期的错误原因),是非常重要的编程技巧。如果您认为某些内容没有(或确实)有效,那么 测试 。它会缩小您的错误搜索范围,并帮助其他人更快地回答您的问题,如果您无法自己解决问题。