How to store the reference of a dictionary element ?
Bengt Richter
bokr at oz.net
Fri Dec 20 17:05:18 EST 2002
On 19 Dec 2002 13:58:22 GMT, bokr at oz.net (Bengt Richter) wrote:
>On 19 Dec 2002 12:29:49 +0800, "Alfredo P. Ricafort" <alpot at mylinuxsite.com> wrote:
>
>>On Wed, 2002-12-18 at 06:36, Bengt Richter wrote:
>>
[...]
>====< menutree.py >==============================================================
>#!/usr/bin/python
># menutree.py for "Alfredo P. Ricafort" <alpot at mylinuxsite.com>
>
>inputData=(
> ('/&File', 'textF0','textF1','F2'),
> ('/File/&New', 'textFN0','textFN1'),
> ('/File/New/&Folder', 'textFNF0','textFNF1'),
> ('/File/New/&Directory', 'textFND0','textFND1','textFND2'),
> ('/&Edit', 'textE0','textE1')
>)
>
>class Node:
> def __init__(self, name, parent=None, attrTup=()):
> __slots__ = ['name','disp','parent', 'children','attrTup'] # optional, saves space
The __slots__ line should not have been in this file. It accidentally did no harm here because
1. it was local to __init__ instead of being a class variable
2. Node did not derive from object.
If it had been inserted correctly, it would have made adding a new attribute dynamically
to a node illegal, as a hack in the test code did, by adding .treeDict. And which I also
did in an interactive log. Instead the logical thing would have been to use the
attrTup slot (maybe in a tuple for consistency with the name or anything else that might
want to see a tuple container there, but not otherwise necessarily).
the updated code is:
====< menutree.py >==============================================================
#!/usr/bin/python
# menutree.py for "Alfredo P. Ricafort" <alpot at mylinuxsite.com>
# 2002-12-20 bokr at oz.net corrected __slots__ usage and the then illegal attr addition in test code
#
inputData=(
('/&File', 'textF0','textF1','F2'),
('/File/&New', 'textFN0','textFN1'),
('/File/New/&Folder', 'textFNF0','textFNF1'),
('/File/New/&Directory', 'textFND0','textFND1','textFND2'),
('/&Edit', 'textE0','textE1')
)
class Node(object):
__slots__ = ['name','disp','parent', 'children','attrTup'] # optional, saves space
def __init__(self, name, parent=None, attrTup=()):
self.name = name.replace('&','') # without shortcut &
self.disp = name # menu display text
self.parent = parent
self.children = []
self.attrTup = attrTup
def addChild(self, child):
if not isinstance(child, Node):
raise ValueError, 'Children must be Node instances, not %s' % type(child)
child.parent = self # the parent link you wanted ;-)
self.children.append(child)
def getChild(self, name):
for child in self.children:
if child.name == name:
return child
raise ValueError, 'Node "%s" has no child named "%s"' % (self.name, name)
def show(self, recurse=0, level=0):
print '%s %-30s"%s" %s' %(level*4*' ', self.name+':', self.disp, self.attrTup)
if recurse:
for child in self.children: child.show(recurse,level+1)
def __repr__(self): return '<Node %s at 0x%08x>' %( `self.name`, id(self))
def makeDict(tree):
treed = {}
def addNodeNameKey(node):
if treed.get(node.name): raise ValueError, 'Non-Unique Node name: %s' % node.name
treed[node.name]=node
for child in node.children: addNodeNameKey(child)
addNodeNameKey(tree)
return treed
makeDict = staticmethod(makeDict)
def makeTree(name, inputData):
tree = Node(name)
for tup in inputData:
path = tup[0].split('/')[1:] # assumes path starts with '/' and no insignificant spaces
currNode = tree
for name in path:
try:
currNode = currNode.getChild(name.replace('&',''))
except ValueError:
child = Node(name, currNode, tup[1:]) # currNode is parent
currNode.addChild(child)
currNode = child
return tree
makeTree = staticmethod(makeTree) # so it can be called without a node instance
def test(inData):
menuTree = Node.makeTree('Menu Bar',inData) # give root node a name
menuTree.show(1,0)
menuTree.attrTup = (Node.makeDict(menuTree),) # attach optional directory for test
return menuTree # so we can print dir showing access via root node
inputData2=( # test out of order and reorderd input
('/File/New/&Directory', 'textFND0','textFND1','textFND2'),
('/File/New/&Folder', 'textFNF0','textFNF1'),
('/&File', 'textF0','textF1','F2'),
('/File/&New', 'textFN0','textFN1'),
('/&Edit', 'textE0','textE1'),
('/File/E&xit', 'TTFN ;-)')
)
if __name__ == '__main__':
def boxit(s):
print ' +-%s-+' % ('-'*len(s))
print ' | %s |' % s
print ' +-%s-+' % ('-'*len(s))
boxit('From ordered data')
root = test(inputData)
boxit('Directory of all nodenames (must be unique) to look up named nodes')
print '{\n%s}' % (''.join([('%s:%s,\n' % (`k`,`v`)) for k,v in root.attrTup[0].items()]))
boxit('Parent links of nodes in dict')
for k,v in root.attrTup[0].items(): print '%15s is parent of %s' % (
v.parent and v.parent.name or '(No parent)', k)
boxit('From out of order & reordered input with added item')
test(inputData2)
=================================================================================
[ test output is the same ]
The part of the interaction that wouldn't have worked started with:
>>> mt2 = menutree.Node.makeTree('Test',menutree.inputData2)
>>> mt2.treeDict = menutree.Node.makeDict(mt2) # attach dict to root
^^^^^^^^^--not legal now without 'treeDict' in the __slots__ list
As we'll show:
>>> import menutree
>>> mt2 = menutree.Node.makeTree('Test',menutree.inputData2)
>>> mt2.treeDict = menutree.Node.makeDict(mt2) # attach dict to root
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'Node' object has no attribute 'treeDict'
Instead we'll put it in the attrTup slot, and then walk around a bit again:
>>> mt2.attrTup = (menutree.Node.makeDict(mt2),) # put dict in root attrTup in tuple
>>> mt2
<Node 'Test' at 0x007d9fd0>
>>> mt2.attrTup[0].keys()
['Directory', 'Exit', 'File', 'Test', 'New', 'Folder', 'Edit']
>>> mt2.attrTup[0]['Exit']
<Node 'Exit' at 0x007d8a90>
>>> mt2.attrTup[0]['Exit'].parent
<Node 'File' at 0x007d8f40>
>>> mt2.attrTup[0]['Exit'].parent.parent
<Node 'Test' at 0x007d9fd0>
>>> mt2.attrTup[0]['Exit'].parent.parent.getChild('File')
<Node 'File' at 0x007d8f40>
>>> mt2.attrTup[0]['Exit'].parent.parent.getChild('File').show(1)
File: "File" ('textFND0', 'textFND1', 'textFND2')
New: "New" ('textFND0', 'textFND1', 'textFND2')
Directory: "&Directory" ('textFND0', 'textFND1', 'textFND2')
Folder: "&Folder" ('textFNF0', 'textFNF1')
Exit: "E&xit" ('TTFN ;-)',)
>>> mt2.attrTup[0]['Exit'].parent.parent.getChild('File').getChild('New').children[1]
<Node 'Folder' at 0x007d9d20>
>>> mt2.attrTup[0]['Exit'].parent.parent.getChild('File').getChild('New').children[1].disp
'&Folder'
And so forth...
>>> mt2.attrTup[0]['Exit'].attrTup[0]
'TTFN ;-)'
Sorry for any confusion caused ;-/
Regards,
Bengt Richter
More information about the Python-list
mailing list