TypeError: on heapq.heapop on python3 but but working in python2

Viewed 173

I am working on a genome compression algorithm using variations of Huffman coding. I have the following piece of code in python2:

def makeHuffTree(trees):
   heapq.heapify(trees)
   while len(trees) > 1:
      childR, childL = heapq.heappop(trees), heapq.heappop(trees)
      parent = (childL[0] + childR[0], childL, childR)
      heapq.heappush(trees, parent)
   return trees[0]

I am trying to run it in python3. But, I am getting a Type error as follows:

TypeError: '<' not supported between instances of 'tuple' and 'str'

The input that goes into the function is a list of tuples. Say,

[(1, '35'), (1, '38'), (1, '50'), (1, 'K'), (4, 'N')]

I am confused, why it is working in python 2 but not in python3. I tried debugging the program and narrowed it down to the line I am getting the error. The module heapq has functions as follows:

def heappop(heap):
    """Pop the smallest item off the heap, maintaining the heap invariant."""
    lastelt = heap.pop()    # raises appropriate IndexError if heap is empty
    if heap:
        returnitem = heap[0]
        heap[0] = lastelt
        _siftup(heap, 0)
        return returnitem
    return lastelt
def _siftup(heap, pos):
    endpos = len(heap)
    startpos = pos
    newitem = heap[pos]
    # Bubble up the smaller child until hitting a leaf.
    childpos = 2*pos + 1    # leftmost child position
    while childpos < endpos:
        # Set childpos to index of smaller child.
        rightpos = childpos + 1
        if rightpos < endpos and not heap[childpos] < heap[rightpos]:
            childpos = rightpos
        # Move the smaller child up.
        heap[pos] = heap[childpos]
        pos = childpos
        childpos = 2*pos + 1
    # The leaf at pos is empty now.  Put newitem there, and bubble it up
    # to its final resting place (by sifting its parents down).
    heap[pos] = newitem
    _siftdown(heap, startpos, pos)
def _siftdown(heap, startpos, pos):
    newitem = heap[pos]
    # Follow the path to the root, moving parents down until finding a place
    # newitem fits.
    while pos > startpos:
        parentpos = (pos - 1) >> 1
        parent = heap[parentpos]
        if newitem < parent:
            heap[pos] = parent
            pos = parentpos
            continue
        break
    heap[pos] = newitem

The error arises after some iterations in the siftup function on line

        if rightpos < endpos and not heap[childpos] < heap[rightpos]:

I tried printing the type of rightpos and endpos, and I do not see an instance of str - every time it is tuple only. Using python2, the function executes successfully and produces the following results after some steps.

input (trees)= [(1, '35'), (1, '38'), (1, '50'), (1, 'K'), (4, 'N')]

[(1, '35'), (1, '38'), (1, '50'), (1, 'K'), (4, 'N')]
Step 1:
[(1, '50'), (1, 'K'), (4, 'N'), (2, (1, '38'), (1, '35'))]
Step 2:
[(2, (1, '38'), (1, '35')), (4, 'N'), (2, (1, 'K'), (1, '50'))]
Step 3:
[(4, 'N'), (4, (2, (1, 'K'), (1, '50')), (2, (1, '38'), (1, '35')))]
Step 4:
(8, (4, (2, (1, 'K'), (1, '50')), (2, (1, '38'), (1, '35'))), (4, 'N'))
Step 5:

but in python 3, I am getting error after this many steps.

input (trees)= [(1, '35'), (1, '38'), (1, '50'), (1, 'K'), (4, 'N')]

[(1, '35'), (1, '38'), (1, '50'), (1, 'K'), (4, 'N')]
Step 1:
[(1, '50'), (1, 'K'), (4, 'N'), (2, (1, '38'), (1, '35'))]
Step 2:
[(2, (1, '38'), (1, '35')), (4, 'N'), (2, (1, 'K'), (1, '50'))]

Afterward, the error occurs: "TypeError: '<' not supported between instances of 'tuple' and 'str' "

I seek assistance, in making the piece of code work in python3.

1 Answers

So, I guess I have figured out the solution to the issue. The problem is due to: python 2 allows comparison between string and tuple but not the python3.

changing line 267:

if rightpos < endpos and not heap[childpos] < heap[rightpos]:

to

if rightpos < endpos and not heap[childpos][0] < heap[rightpos][0]:

and line 212:

if newitem < parent:

to

if newitem[0] < parent[0]:

on the library https://github.com/python/cpython/blob/3.8/Lib/heapq.py

fixed my issue.

I overwrote the functions, locally.

Related