链表;类型错误:__str__ 返回非字符串(类型 NoneType)

问题描述 投票:0回答:1

我正在研究Python 3.11中的链表。我编写了书中给出的代码。代码如下:

class Node:
    def __init__(self, data, next=None):
        self.data = data
        self.next = next

class LinkedList:
    def __init__(self):
        self.head = None

    def __str__(self):
        node = self.head
        while node is not None:
            print(node.data)
            node = node.next

    def append(self, data):
        if not self.head:
            self.head = Node(data)
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = Node(data)

    def search(self, target):
        current = self.head
        while current.next:
            if current.data == target:
                return True
            else:
                current = current.next
        return False

    def remove(self, target):
        if self.head == target:
            self.head = self.head.next
            return
        current = self.head
        previous = None
        while current:
            if current.data == target:
                previous.next = current.next
            previous = current
            current = current.next

    def reverse_list(self):
        current = self.head
        previous = None
        while current:
            next = current.next
            current.next = previous
            previous = current
            current = next
        self.head = previous

a_list = LinkedList()
a_list.append("Tuesday")
a_list.append("Wednesday")
print(a_list)

import random

a_list = LinkedList()

for i in range(0, 20):
    j = random.randint(1, 30)
    a_list.search(j)
    print(j, end=' ')

当我运行此代码时,出现错误:

回溯(最近一次调用最后一次): 文件 linked_list.py,第 62 行,位于 打印(a_列表) 类型错误:str返回非字符串(类型为NoneType)

由于函数str出现问题,我尝试了以下操作(最后添加 return ): 1)

def __str__(self):
        node = self.head
        while node is not None:
            print(node.data)
            node = node.next
        return node

结果是一样的:

回溯(最近一次调用最后一次): 文件 linked_list.py,第 62 行,位于 打印(a_列表) 类型错误:str返回非字符串(类型为NoneType)

2)

def __str__(self):
        node = self.head
        while node is not None:
            print(node.data)
            node = node.next
        return node.data

结果:

回溯(最近一次调用最后一次): 文件“linked_list.py”,第 63 行,位于 打印(a_列表) 文件“linked_list.py”,第 18 行,位于 str 中 返回节点数据 AttributeError:“NoneType”对象没有属性“data”

python python-3.x linked-list
1个回答
0
投票

您的代码中存在多个问题:

  • 你问的问题:

    __str__
    的作者错误地认为应该打印列表的内容。这不是
    __str__
    的目的。相反,它应该返回列表的字符串版本。调用者可以对该字符串执行某些操作,可以打印它或执行其他操作。

    一个快速修复方法是将

    print
    调用替换为将数据连接成字符串然后返回它的代码:

    def __str__(self):
        s = ""
        node = self.head
        while node is not None:
            s += f"{node.data} "  # don't print, but collect in a string
            node = node.next
        return s
    

    但这并不是最优雅的方式。您可以从首先定义

    __iter__
    中受益,这对于其他目的也很有用......

  • search
    具有检查
    current.next
    但不确保
    current
    不是
    None
    的条件。因此,当列表为空时,此代码将遇到错误。其次,当最后一个节点(仅)具有搜索到的数据时,它不会找到匹配项。条件应该是
    current
    ,而不是
    current.next

  • remove
    head
    target
    进行比较,也将
    current.data
    target
    进行比较。这是不一致的。该函数可以使用节点实例或数据来调用。现在你有了一个混合。我想您希望使用
    data
    来调用 remove,因此第一个
    if
    语句是错误的。你应该先检查链表是否有节点,然后检查头节点的数据。

  • remove
    在删除节点后继续循环,尝试找到更多匹配项。这很好,但它与处理头节点中的匹配的方式不一致,因为当存在匹配时,您将退出该函数。为了保持一致,您不应该退出那里,并继续前进(检查头部,然后检查其余节点)。

  • remove
    在循环中找到匹配项时,会将
    previous
    更新为已删除的节点。这是不正确的。在这种情况下,
    previous
    应保持不变并引用现在已删除节点之前的节点。

不是问题,但是:

  • 驱动程序代码调用
    a_list.search(j)
    但不对返回值执行任何操作,因此它是无用的。
  • 随机“测试”不会向列表添加任何节点——它仍然是空的。如果将随机值添加到列表中会更有意义,之后您可以对
    search
    方法进行一些正向和负向测试。
  • 名称
    search
    并未表明它返回布尔值(而不是节点或位置)。称之为
    has
    includes
    contains
    。或者更好的是,定义
    __contains__
    ,这样您就可以使用
    in
    运算符来代替。
  • 名称
    _list
    中不需要添加
    reverse_list
    。这是链表上的方法,因此很明显,反转涉及(链表)。

这里是

LinkedList
类的建议代码:

class LinkedList:
    def __init__(self):
        self.head = None

    def __iter__(self):  # Make linked list iterable
        node = self.head
        while node:
            yield node.data
            node = node.next
    
    def __str__(self):  # Don't print, but return str
        # Make use of __iter__
        return " ".join(map(str, self))

    def append(self, data):
        if not self.head:
            self.head = Node(data)
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = Node(data)

    def __contains__(self, target):  # Support IN operator
        current = self.head
        while current:  # fixed condition
            if current.data == target:
                return True
            current = current.next  # No need for ELSE
        return False

    def remove(self, target):
        # Check in a loop, and don't return:
        while self.head and self.head.data == target:  # compare data, not node
            self.head = self.head.next
        current = self.head
        previous = None
        while current:
            if current.data == target:
                previous.next = current.next
            else:  # Only update previous when there is no match
                previous = current
            current = current.next

    def reverse(self):  # Better name
        current = self.head
        previous = None
        while current:
            next = current.next
            current.next = previous
            previous = current
            current = next
        self.head = previous
© www.soinside.com 2019 - 2024. All rights reserved.