-1

This seems like a bug to me where I couldn't really figure it out why.

I have a very simple self-defined LinkedList class:

class MyLinkedList:

    def __init__(self):
        self.head = None

    def __iter__(self):
        self.currNode = self.head
        return self

    def __next__(self):
        if self.currNode:
            res = self.currNode
            self.currNode = self.currNode.next
            return res
        else:
            raise StopIteration

    def addAtHead(self, val: int) -> None:
        currNode = self.head

        self.head = Node(val, currNode)

The problem comes inside iter method. After I added a node at head to a empty linkedList, the iter still think the self.head is None! In debug node, I can see self.head is a valid not none instance, but after assigning its value to self.currNode, self.currNode turns out to be None.

I thought it can be a problem of property issue so I changed the attribute to a property. But the problem still exists. Where am I wrong?

    @property
    def head(self):
        return self._head

    @head.setter
    def head(self, x):
        self._head = x

enter image description here

Adding my calling stack:

    ll = MyLinkedList()
    ll.addAtTail(6)
    ll.addAtHead(5)
    ll[0] # is None 

    #where a __getitem__ is defined as:
    def __getitem__(self, i):
        n = 0
        for node in self:
            if n == i:
                return node
            n += 1
        raise IndexError


class Node:
    def __init__(self, val=None, next=None):
        self.val = val
        self.next = next         
20
  • 2
    Don't make a list its own iterator. Some tutorials suggest doing that, but it's a really bad idea, since it breaks if you try to use nested loops or iterate over the list concurrently or reentrantly. Commented May 15, 2020 at 21:25
  • 1
    "the iter still think the self.head is None!" I don't understand; the screenshot you show of the debugger clearly shows head = {Node} .... At any rate, can you show an example of trying to use the class that causes an unexpected error? IDEs don't always get everything right, or they may show things out of sync. Commented May 15, 2020 at 21:27
  • 2
    You need to show how you're using this (with minimal reproducible example) for us to provide a complete answer, but the main issue is likely that you haven't written an iterator class. Iterators must have idempotent __iter__ methods (in 99.99% of cases they should do nothing but return self), as Python assumes it can blithely call __iter__ on an existing iterator and change nothing. If you want this to be an iterable, __next__ should not be defined, and, usually, you write __iter__ as a generator function (migrating all the logic into __iter__ and using yield where __next__ would use return). Commented May 15, 2020 at 21:29
  • 1
    @user1438644: That's a different thing. The node isn't supposed to be an iterator. Commented May 15, 2020 at 21:55
  • 1
    I can't reproduce your issue, though maybe I'm doing something different than you are, since it's a little hard to tell what exactly you're running. I used the MyLinkedList class from your first block with the addition of the __getitem__ method in your last block. I also created the Node class from your last block. Then the rest of the code in the last block worked fine. I get a node when I do ll[0]. Commented May 15, 2020 at 22:54

1 Answer 1

0
class Node:
    def __init__(self, val=None, nxt=None):
        self.val = val
        self.n = nxt 

class MyLinkedList:

    def __init__(self):
        self.head = None

    def __iter__(self):
        self.currNode = self.head
        return self

    def __next__(self):
        if self.currNode:
            res = self.currNode.val
            self.currNode = self.currNode.n
            return res
        else:
            raise StopIteration

    def addAtHead(self, val: int) -> None:
        currNode = self.head

        self.head = Node(val, currNode)


n = MyLinkedList()
n.addAtHead(4)
n.addAtHead(5)
n.addAtHead(7)

for i in n:
    print(i)

got

7
5
4
Sign up to request clarification or add additional context in comments.

2 Comments

Is this why you thought next needed to be a method? You could just access the value through val. You don't need a method for that. next was intended to be the link to the next node in the original code. It wasn't supposed to be a value accessor. Naming a node value accessor next is a weird name choice.
An answer without a word values nothing, you may explain what the problem was, and what you did to solve it, and why does it solves it

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.