从Python中LeetCode的Solution类理解关键字self

jdzmm42g  于 2023-05-19  发布在  Python
关注(0)|答案(1)|浏览(130)

我正在尝试学习Python,并正在使用LeetCode进行练习。Problem 1721要求我们写一个函数,当传入链表时,该函数将成对交换相邻节点。例如:

Input : [A, B, C, D, E, F, G]
Output: [B, A, D, C, F, E, G]

我自己能想出一个解决方案,但我不明白下面的另一个解决方案。当作者写pre = self时,pre到底绑定到什么?我对关键字self的理解使我相信它指的是Solution类的示例,但我不知道这将如何帮助解决问题。我们不应该只处理链表吗?

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre, pre.next = self, head
        while pre.next and pre.next.next:
            a = pre.next
            b = a.next
            pre.next, b.next, a.next = b, a, b.next
            pre = a
        return self.next

我读过其他几个问题和其他介绍self的网站,但它们都只提供了非常基本的构造函数和其他琐碎函数的示例。我不明白self.next在这里是什么意思。
这是我在这个论坛上的第一个问题,所以如果有任何方法可以改进这个问题,请让我知道。先谢谢你。

ru9i0ody

ru9i0ody1#

这个解决方案以一种相当“创造性”的方式使用了self。这里的selfSolution的示例--由LeetCode框架在执行类似下面的代码时创建:

solution = Solution()
head = ListNode(1, ListNode(2, ListNode(3)))
newHead = solution.swapPairs(head)
# ... continue to verify the returned result

以这种方式使用self看起来很奇怪,因为self不是ListNode示例,也没有next属性。下面的语句实际上是在self创建了一个next属性:

pre, pre.next = self, head

因此,循环将很高兴地访问这个next属性,而不必知道它实际上不属于ListNode示例。循环结束后,可以检索next属性以返回最终列表。
这段代码的作者认为(ab)使用self作为虚拟节点。更常见的做法是创建这样一个虚拟节点,如下所示:

class Solution(object):
    def swapPairs(self, head):
        dummy = ListNode()  # The node's value is not relevant -- never used
        pre, pre.next = dummy, head
        while pre.next and pre.next.next:
            a = pre.next
            b = a.next
            pre.next, b.next, a.next = b, a, b.next
            pre = a
        return dummy.next

作者没有创建这个节点,而是重用LeetCode的解决方案示例,从而节省了一点内存(和一行代码)。
我不建议做这样的事情,因为:

  • 它模糊了代码的含义;
  • 它在Solutioninstance 上留下了对列表的引用。这是调用方可能没有意识到的副作用,可能会阻止某些垃圾收集的发生。

相关问题