简体   繁体   中英

Implementing Iter for doubly-linked list

Problem: Being new to python I am currently trying to learn the ropes, getting a better handle on the difference between an array and a linked structure. I've attempted creating a linked list class to assist in getting a better understanding of the language and its structures. What I have written so far:

class LinkedList:
    class Node:
        def __init__(self, val, prior=None, next=None):
            self.val = val
            self.prior = prior
            self.next  = next

    def __init__(self):
        self.head = LinkedList.Node(None) 
        self.head.prior = self.head.next = self.head 
        self.length = 0

    def __str__(self):
        if len(self)==0:
            return '[]'
        else:
            return '[' +  ', '.join(str(x) for x in self) + ']'

    def __repr__(self):
        """Supports REPL inspection. (Same behavior as `str`.)"""
        return str(self)

    def __len__(self):
        """Implements `len(self)`"""
        return self.length

    def __iter__(self):
        """Supports iteration (via `iter(self)`)"""
        cursor = self.head
        while cursor:
            yield cursor.val
            cursor = cursor.next

    def append(self, value):
        n = LinkedList.Node(value, prior=self.head.prior, next=self.head)
        n.prior.next = n.next.prior = n
        self.length += 1

Testing the code below, I'll have a problem where the kernel task won't end, or the debugger will point to line 7 of the test code where it failed. I don't think my __repr__ method is wrong which is why I ask, how could I edit the __iter__ method body to fix this issue? I thought all I had to do was loop through the values in cursor.

from unittest import TestCase
tc = TestCase()

lst = LinkedList()
for d in (10, 20, 30, 40, 50):
    lst.append(d)
tc.assertEqual('[10, 20, 30, 40, 50]', str(lst))
tc.assertEqual('[10, 20, 30, 40, 50]', repr(lst))

Since you say self.head is the sentinel node, your __iter__ is incorrect; it's testing as if it expects to find a "falsy" value (eg None ), when being circularly linked, it will never reach such a point. Presumably, you want something like:

def __iter__(self):
    """Supports iteration (via `iter(self)`)"""
    cursor = self.head.next  # Must advance past non-valued head
    # Done when we get back to head
    while cursor is not self.head:
        yield cursor.val
        cursor = cursor.next

You have a circular list. I diagnosed this with the usual high-tech method: the print statement. :-)

I inserted a couple of prints into your str method:

def __str__(self):
    if len(self)==0:
        return '[]'
    else:
        print "NODE VALUE:", self.head.val
        for x in self:
            print "LIST ITEM", x
        return '[' +  ', '.join(str(x) for x in self) + ']'

... and cut back the test a touch:

lst = LinkedList()
for d in (10, 20, 30, 40, 50):
    lst.append(d)
print "str\t", str(lst)

Your method loops through the five expected values and a None header.

LIST ITEM None
LIST ITEM 10
LIST ITEM 20
LIST ITEM 30
LIST ITEM 40
LIST ITEM 50
LIST ITEM None
LIST ITEM 10
LIST ITEM 20
LIST ITEM 30
LIST ITEM 40
LIST ITEM 50
LIST ITEM None
LIST ITEM 10
LIST ITEM 20

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM