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

Linked list; TypeError: __str__ returned non-string (type NoneType)

提问人:Elnur 提问时间:11/14/2023 最后编辑:Elnur 更新时间:11/14/2023 访问量:50

问:

我正在研究 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_list) TypeError: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_list) TypeError: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_list) 文件“linked_list.py”,第 18 行,在 str 中返回 node.data AttributeError:“NoneType”对象没有属性“data”

python-3.x 链接列表

评论

2赞 Codist 11/14/2023
重写 __str__ 时,必须返回 str 类型
3赞 Karl Knechtel 11/14/2023
你已经采取了正确的步骤来回答,但现在之前的尝试与剩下的问题无关,最后一步是一个简单的逻辑疏忽,不值得提问。仔细考虑循环。如果你这样做了,你对循环了解多少?使用这个结果有意义吗?循环的目的是找到“最后一个”节点,对吧?你能想到关于那个节点的有趣事情吗?您知道如何使用它来修复循环条件吗?while node is not None:node.data
0赞 Karl Knechtel 11/14/2023
请记住,Stack Overflow 不是一个讨论论坛。我们要求每个问题一个问题;这里的目的不是讨论你正在解决的问题,然后让其他人帮助你完成剩下的工作。目的是发布一些可以帮助构建可搜索库的内容。
0赞 Alex Hall 11/14/2023
放进去并不意味着会返回打印的东西。返回和打印是分开的。使用循环构建一个字符串并返回该字符串。print__str____str__

答:

0赞 trincot 11/14/2023 #1

代码中存在多个问题:

  • 你问的问题:作者错误地认为它应该打印列表的内容。这不是 的目的。相反,它应该返回列表的字符串版本。调用方可以对此字符串执行某些操作,该字符串可能是打印它或其他内容。__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有一个条件,它检查但没有确保它不是.因此,当列表为空时,此代码将遇到错误。其次,当最后一个节点(仅)具有搜索到的数据时,它不会找到匹配项。条件应为 on ,而不是current.nextcurrentNonecurrentcurrent.next

  • remove与 和 进行比较。这是不一致的。该函数要么使用节点实例调用,要么使用数据调用。现在你有了一个混合。我想你想用数据来调用,所以第一个陈述是错误的。应首先检查列表是否有节点,然后检查头节点的数据。headtargetcurrent.datatargetremoveif

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

  • 当在循环中找到匹配项时,它会更新为已删除的节点。这是不正确的。例如,这意味着仅删除两个连续匹配节点中的一个。如果匹配项一致,则应保持不变,并引用现在已删除的节点之前的节点。removepreviousprevious

没问题,但是:

  • 驱动程序代码调用但不对返回的值执行任何操作,因此它毫无用处。a_list.search(j)
  • 这个随机的“测试”不会向列表中添加任何节点——它仍然是空的。如果将随机值添加到列表中会更有意义,然后您可以对该方法进行一些正面和负面测试。search
  • 该名称不会显示它返回布尔值(而不是节点或位置)。称其为 or 或 。或者更好的是,定义 ,以便您可以改用运算符。或者更好的是:当你定义了它时,它将被用来解释运算符,所以你实际上可以完全放弃这个方法。searchhasincludescontains__contains__in__iter__insearch
  • 在名称中添加 是不必要的。这是链表上的一种方法,因此很明显,反转涉及(链接)列表。_listreverse_list

以下是该类的建议代码:LinkedList

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

    def __iter__(self):  # Make linked list iterable. Also supports IN operator
        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 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

驱动程序代码可以是:

a_list = LinkedList()
a_list.append("Tuesday")
a_list.append("Wednesday")
a_list.append("Wednesday")
a_list.append("Thursday")
print(a_list)
a_list.remove("Wednesday")
print("Does it have Tuesday? ", "Tuesday" in a_list)
print(*a_list)