Here is code, which you can play with before installing and using the superior blist package from pypi. I did it as therapy after doing programming test answer using zillion of setters and getters. Motivation is basically to show why you should use properties after you need them and attribute access before that. The function of before and after links is exchangable, so you can do reversing of directions of double linked list by just sweeping through list and toggling the flag. If that quite a hackish feature would not be there we would not need to use property. Here it is done only to demostrate the ease of making attributes to properties afterwards.

def insert_ordered(at_me, new_dlist):
    at_me: a DoublyLinked that is part of a doubly linked list
    new_dlist:  a DoublyLinked with no links 
    This procedure appropriately inserts new_dlist into the linked list that at_me is a part of.    
    new_name =
    while at_me.before and new_name <=
        at_me = at_me.before
    while at_me.after and < new_name:
        at_me = at_me.after
    if at_me.before is None and new_name <
        new_dlist.after, at_me.before = at_me, new_dlist
    elif at_me.after is None and new_name >
        at_me.after, new_dlist.before = new_dlist, at_me
        if at_me.after:
            at_me.after.before = new_dlist
        new_dlist.before, new_dlist.after, at_me.after = at_me, at_me.after, new_dlist
def find_front(start):
    #return find_front(start.before) if start.before else start
    while start.before is not None:
        start = start.before
    return start
def find_end(start):
    #return find_front(start.before) if start.before else start
    while start.after is not None:
        start = start.after
    return start
def print_dl(here):
    print '<->'.join(find_front(here))

def link_check(start):
    here = find_front(start)
    while here.after:
        check = here
        here = here.after
        assert here.before == check, '%s before links inconsistent: %s != %s' % (
                                            here, here.before, check)
        assert == or ( > == (not here.reversed), '%s before name more than this word: %s < %s' % (here,,

class DoublyLinked(object):
    def __init__(self, name, before=None, after=None): = name
        self._before = before
        self._after = after
        self.reversed = False
    insert_ordered = insert_ordered
    find_front, find_end = find_front, find_end
    start_node, end_node = property(find_front), property(find_end)
    def before(self):
        return self._after if self.reversed else self._before
    def before(self, value):
        if self.reversed:
            self._after = value
            self._before = value   
    def after(self):
        return self._before if self.reversed else self._after   
    def after(self, value):
        if self.reversed:
            self._before = value
            self._after = value
    def reverse(self):
        node = self.find_front()
        while node is not None:
            node.reversed = not node.reversed
            # old node after is changed to before because of reverse, so we must use that
            node = node.before
    def __getitem__(self, n):
        if n >= 0:
            place = self.start_node
            reverse = False
            n = -n + 1
            reverse = True
            place = self.end_node
        for _ in range(n):
                place = place.after if not reverse else place.before
            except AttributeError as e:
                raise IndexError('Index out of bounds!')

    def __len__(self):
        return sum(1 for _ in self)

    def __iter__(self):
        here = self.start_node
        while here is not None:
            here = here.after

    def find(self, value):
        for ind, v in enumerate(self.start_node):
            if v == value:
                return ind
    def __str__(self):
        return '%s <- %s -> %s' % (
            ( if self.before else None),
            (  if self.after else None))
    def __repr__(self):
        return 'DoublyLinked(%r, %r, %r)' % (,
                                    if self.before else None,
                                    if self.after else None)

if __name__ == '__main__':
    import random
    p = ['eric', 'andrew','fred', 'martha', 'ruth']
    p += random.sample(p, 2)
    p = ['eda']*2 + p
    ##p = ['eda', 'eda', 'martha', 'andrew', 'ruth', 'andrew', 'eric', 'fred', 'ruth']
    for test in range(len(p)):
        s = iter(p)
        double_list = DoublyLinked(next(s))
        for name in s:
            insert_ordered(double_list, DoublyLinked(name))
        p.insert(0, p.pop())
        print ('='*30)
    print 'reversed'
    print 'Name at %ith position is: %s' % (4, double_list[4])
    print 'Name at %ith position is: %s' % (-2, double_list[-2])
    print 'reversed back'
    print 'Name at %ith position is: %s' % (4, double_list[4])
    for v in 'eda', 'dea':
        print "%r is in double_list: %s" % (v, v in double_list)
        print "index is %s" % (double_list.find(v))
    print 'Length of the list is', len(double_list)

IT/Science/Contracts/Religious translation/interpreting FIN-ENG-FIN
Python programming

The article starter has earned a lot of community kudos, and such articles offer a bounty for quality replies.