oDium oDium - 5 months ago 12
Python Question

How to write equals method

Situation: I'm trying to get a good handle on the doubly-linked structure. I've got a decent grip on the methods so far. I want to be able to create two objects for this class and check if every item in it is equal. I don't have any syntax errors, and the error I'm getting is kind of confusing. So here's what I have 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) # sentinel node (never to be removed)
self.head.prior = self.head.next = self.head # set up "circular" topology
self.length = 0

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

def _normalize_idx(self, idx):
nidx = idx
if nidx < 0:
nidx += len(self)
if nidx < -1:
raise IndexError
return nidx

def __getitem__(self, idx):
"""Implements `x = self[idx]`"""
nidx = self._normalize_idx(idx)
currNode = self.head.next
for i in range(nidx):
currNode = currNode.next
if nidx >= len(self):
raise IndexError
return currNode.val

def __setitem__(self, idx, value):
"""Implements `self[idx] = x`"""
nidx = self._normalize_idx(idx)
currNode = self.head.next
if nidx >= len(self):
raise IndexError
for i in range(nidx):
currNode = currNode.next
currNode.val = value

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

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

def __eq__(self, other):
currNode = self.head.next
currNode2 = other.head.next
for currNode, currNode2 in zip(self, other):
if currNode.val != currNode2.val:
return False
return True


from unittest import TestCase
tc = TestCase()
lst = LinkedList()
lst2 = LinkedList()

tc.assertEqual(lst, lst2)

tc.assertNotEqual(lst, lst2)

When I test this code I get I get an Assertion error saying "
[] == [100]
" I'm unsure why my code recognizes this as equal, when I want it to actually check specific values in the node.


zip only goes as far as the shortest list. You want itertools.zip_longest, and you don't want .val (your iterator returns the actual values already). Try this:

def __eq__(self, other):
    for val1, val2 in zip_longest(self, other):
        if val1 != val2:
            return False
    return True

or perhaps better?

def __eq__(self, other):
    return all(val1 == val2 for val1, val2 in zip_longest(self, other))


I like @BrenBarn's suggestion of checking length first. Here's a more efficient answer:

def __eq__(self, other):
    return len(self) == len(other) and all(
        val1 == val2 for val1, val2 in zip(self, other))