[Tutor] Strange namespace issue

Alexandre Ratti alex@gabuzomeu.net
Wed, 03 Apr 2002 20:39:36 +0200


Hello,


I ran into this strange issue a couple of days ago. I'd be grateful if 
someone could explain it. Sorry for this long, rambling account; I tried to 
make it as clear as possible.

I wanted to parse a string into a tree for later processing. I created this 
class (based on the Trees chapter of "How to think like a computer 
scientist"). It defines a "multiple" tree, eg. a tree whose nodes can have 
several subnodes.

Here is the 1st version:

class TreeNode:
     "Node to build multiple trees."

     def __init__(self, cargo = None, nodeList = []):
         self.cargo = cargo
         self.nodeList = nodeList

     def addNode(self, node):
         "Add a TreeNode instance to the child node list."
         if node:
             self.nodeList.append(node)

     def __getitem__(self, index):
         "Return a child node."
         return self.nodeList[index]
...

I used another class to recursively cut a text snippet into pieces and 
store them in tree nodes, thus building a tree. Here is a short except of 
the main parsing method. The point I want to make is that I invoked the 
class using "node = TreeNode(someCargoObject)"; eg. I did not pass a list 
argument when creating a node instance. Then I appended the new node to the 
current tree node.

     def doParse(self, patternList, tree, workText):
         "Recursively parse wiki formatting into a tree."
...
                     pattern = NullPattern(textBefore)
                     node = TreeNode(pattern)
                     tree.addNode(node)
                     self.doParse(patternList[:-1], node, textBefore)

When trying to print out the tree content, I ran into an endless loop. Here 
is the printing code (I eventually added a test to break out of the loop 
before I had to forcefully close PythonWin :-).

testDict = {}

def printTree(tree, level = 0):
     if not tree:
         return
     print "  " * level + "|_", [str(tree.cargo)]
     for node in tree:
         if testDict.has_key(id(node)):
             print id(node), str(node)
             raise "Duplicated Node Error"
         else:
             testDict[id(node)] = None
         printTree(node, level + 1)

The tree looked OK (eg. I printed out the id for every node and it looked 
sane). After a long fight, I realised that all nodes used a common nodeList 
instance (with the same id)...

When I rewrote the __init__ method, the problem went away:

     def __init__(self, cargo = None, nodeList = None):
         "Initialise the node instance."
         self.cargo = cargo
         if nodeList:
             self.nodeList = nodeList
         else:
             self.nodeList = []

And now I get to my query: when I wrote...

     def __init__(self, cargo = None, nodeList = []):
         self.cargo = cargo
         self.nodeList = nodeList

... I expected self.nodeList to be initialised to a new, empty list if the 
constructor was called without a nodeList argument. Somehow it failed. I 
had to use "nodeList = None" in the argument list and then to specify 
"self.nodeList = []" to initialise the list properly.

What did I miss? Is this the normal behaviour?

This happened on WinNT 4 with Python 2.1.2. I can upload the complete code 
somewhere if needed.


Many thanks.

Alexandre