Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Iterators on Linked List Elements

I apologize in advance if this question is misplaced or duplicate.

This question is similar in nature to doubly Linked list iterator python.

However, unlike the referenced question, I don't wish to create a overarching linked list object which contains a lot of metadata and provides the iterator (they are not necessary for my application).

My question is: Is there any fundamental reason why I should not or can not provide an iterator that doesn't iterate over elements it contains, but instead jumps through distinct element objects that are linked to each other via references?

The iterator is not necessary for proper functioning of the code, but I rather like the syntactic sugar of the for item in construction.

My implementation looks a bit like this (simplified version):

class LinkedAccount:
    def __init__(self, someParameter, nextAccount = None, prevAccount = None):

        self.someParameter = someParameter

        self.next = nextAccount
        self.prev = prevAccount
        if nextAccount is not None:
            self._tell_next()
        if prevAccount is not None:
            self._tell_prev()

    def _tell_next(self):
        if self.next is not None:
            self.next._recv_next(self)

    def _recv_next(self,prevAccount):
        self.prev = prevAccount

    def _tell_prev(self):
        if self.prev is not None:
            self.prev._recv_prev(self)

    def _recv_prev(self,nextAccount):
        self.next = nextAccount


    def __iter__(self):
        return AccountIterator(self)

class AccountIterator:
    def __init__(self,Account):
        self.Account = Account

    def __iter__(self):
        return self

    def next(self):
        if self.Account is None:
            raise StopIteration
        else:
            curAccount = self.Account
            self.Account = self.Account.next
            return curAccount

The LinkedAccount object provides an iterator that iterates from one LinkedAccount to the next, using the .next parameter already stored in the LinkedAccount object.

This approach appears to work, but the python iterator documentation seems to assume that the iterator is going to walk through elements contained by the parent object. Are there any pitfalls that preclude me doing something like this?

Thanks!

like image 793
Hao Cheng Avatar asked Nov 01 '13 05:11

Hao Cheng


1 Answers

It sounds like it would work but it is semantically weird for the exact reason you mentioned. Having the __iter__ defined on LinkedAccount makes it sound like you're iterating over the account itself and not a list of accounts. What you have now makes it seem like you're setting up lines of code like this:

for list_item in head_of_list:

Which makes no sense. In this case I think you could just def a simple generator:

 def iterate_from(list_item):
     while list_item is not None:
         yield list_item
         list_item = list_item.next

Which allows you to write code like this:

for list_item in iterate_from(head_of_list):
like image 137
Free Monica Cellio Avatar answered Oct 04 '22 12:10

Free Monica Cellio