EDIT: Okay, discussion of your examples.
- Example 1: (Reversing linked list using recursion)
Pretty simple: the "helper" function is a general recursive function that will work on any node in the class that has a linked list. Then the wrapper is a method function that knows how to find self.head
, the head of the list. This "helper" is a class member function, but it could also be a simple function in a general data-structures stuff library. (This makes more sense in Python than in languages like C, because a function like this could work with any linked list that is a class with a member called forward
as its "next pointer" value. So you really could write this once and then use it with multiple classes that implement linked lists.)
- Example 2: (Binary Search Tree)
The actual recursive function returns None
if no node can be found with the specified key
. Then there are two wrappers: one that implements __contains__()
, which works just fine if it returns None
; and valueOf()
, which raises an exception if the key is not found. As the comment notes, two wrappers lets us solve two different problems with a single recursive function.
Also, just as with the first example, the two wrappers kick off the search in a specific location: self._root
, the root of the tree. The actual recursive function can be started anywhere inside a tree.
If __contains__()
were implemented with a default argument of a node to search, and the default was set to some unique value, it could check for the special value and start at the root in that case. Then when __contains__()
is called normally, the unique value would be passed in, and the recursive function could know that it needs to look at the special location self._root
. (You can't just pass in self._root
as the default value, because the default value is set at compile time, and the class instance can change after that, so it wouldn't work right.)
class UniqueValue:
pass
def __contains__(self, key, subtree=UniqueValue):
if subtree is UniqueValue:
subtree = self._root
if subtree is None: # base case
return None
elif key < subtree.key: # target is left of the subtree root
return self.__contains__(key, subtree.left)
elif key > subtree.key: # target is right of the subtree root
return self.__contains__(key, subtree.right)
else: # base case
return subtree
Note that while I said it could be implemented as I show here, I didn't say I prefer it. Actually I prefer the two wrappers version. This is a little bit tricky, and it wastes time on every recursive call checking to see if subtree is UniqueValue
. More complex and wastes time... not a win! Just write the two wrappers, which start it off in the right place. Simple.