1

I am studying the following implementation1 in :

class TreeNode():
    def __init__(self, key, val,
                       lc = None, rc = None, parent = None):
        self.key = key
        self.val = val
        self.leftChild = lc
        self.rightChild = rc
        self.parent = parent

    def hasLeftChild(self):
        return not self.leftChild is None

    def hasRightChild(self):
        return not self.rightChild is None

    # in-order iterator
    def __iter__(self):
        if self:
            if self.hasLeftChild():
                for elem in self.leftChild:
                    yield elem

            yield self.key

            if self.hasRightChild():
                for elem in self.rightChild:
                    yield elem                    


class BinarySearchTree():
    def __init__(self):
        self.root = None
        self.size = 0

    def length(self):
        return self.size

    def __len__(self):
        return self.size

    def put(self, key, val):
        if not self.root:
            self.root = TreeNode(key, val)
        else:
            self._put(key, val, self.root)

    def _put(self, key, val, currentNode):
        if currentNode.key >= key:
            if currentNode.hasLeftChild():
                self._put(key, val, currentNode.leftChild)
            else:
                currentNode.leftChild = TreeNode(key, val, parent = currentNode)
        else:
            if currentNode.hasRightChild():
                self._put(key, val, currentNode.rightChild)
            else:
                currentNode.rightChild = TreeNode(key, val, parent = currentNode)

Let's consider this example caller code:

from random import randint

bst = BinarySearchTree()

keys = [5, 30, 2, 40, 25, 4]

for key in keys:
    bst.put(key, randint(1000, 2000))

# in-order iteration      
for key in bst.root:
    print(key)

producing the expected output:

2  
4  
5  
25 
30 
40 

What is happening behind the scenes when the for loop used for the in-order iteration in the caller code is executed?

I know that the __iter__ method of the TreeNode class recursively calls itself in the two for loops for the left and right sub-trees.
What I don't manage to grasp is the effect of yield elem in those for loops:

          if self.hasLeftChild():
              for elem in self.leftChild:
                  yield elem

and

          if self.hasRightChild():
              for elem in self.rightChild:
                  yield elem

with respect to the effect of yield self.key, which apparently concerns the usual implementation of the protocol as explained in the docs.

More specifically, what is the content of the elem variable that is returned by yield elem in the above-mentioned nested for loops, as opposed to the content of self.key (which is the actual key data in the TreeNode object) returned by yield self.key?


  1. This is an excerpt from the implementation given in Problem Solving with Algorithms and Data Structures using Python by Brad Miller and David Ranum.
tony
  • 431
  • 4
  • 12
  • Do you need help understanding the `yield` keyword as a whole or just in this context? – ikkuh Dec 20 '17 at 12:47
  • @ikkuh Just in this context and possibly in similar ones where recursion is also involved. – tony Dec 20 '17 at 12:53
  • @pycoder I read and I am presently re-reading that post, but I still don't manage to come up with a clear picture in this context. – tony Dec 20 '17 at 12:59

0 Answers0