202 lines
5.5 KiB
Python
202 lines
5.5 KiB
Python
'''
|
|
Simple Hierarchic Walking functions for use with hierobj-type objects.
|
|
|
|
Provide for recurse-safe processing. Currently only provide depth-first
|
|
processing, and don't provide means for ignoring branches of the tree
|
|
during processing. For an example of breadth-first processing, see
|
|
mcf.pars.int.index.indutils. For more complex hierarchic processing,
|
|
see the mcf.walker package.
|
|
|
|
Originally these functions were only methods of the hierobj class (they
|
|
still are methods of it). I've split them out to allow them to be
|
|
imported selectively by other classes (some classes will only want
|
|
the simple walking functions, and not want to be bothered with the
|
|
methods which hierobj uses to keep track of its particular internal
|
|
structures.
|
|
'''
|
|
|
|
def hier_rapply(self, function,arglist=None,argdict={},moreattr = '__childlist__'):
|
|
'''
|
|
Safely apply a function to self and all children for
|
|
the function's side effects. Discard the return values
|
|
that function returns.
|
|
|
|
function
|
|
function to apply
|
|
arglist
|
|
(self,)+arglist is the set of arguments passed to function
|
|
argdict
|
|
passed as namedargs to the function
|
|
moreattr
|
|
the attribute representing the children of a node
|
|
'''
|
|
alreadydone = {}
|
|
tobedone = [self]
|
|
if arglist or argdict:
|
|
if not arglist: arglist=[self]
|
|
else:
|
|
arglist.insert(0,self) # we could insert anything... self is convenient
|
|
while tobedone:
|
|
object = tobedone[0]
|
|
try:
|
|
alreadydone[id(object)]
|
|
# We've already processed this object
|
|
except KeyError:
|
|
# We haven't processed this object
|
|
alreadydone[id(object)]=1
|
|
arglist[0]=object
|
|
apply(function,tuple(arglist),argdict)
|
|
try:
|
|
tobedone[1:1]=getattr(object,moreattr)
|
|
except AttributeError:
|
|
# if the object isn't a hierobj, we don't need to recurse into it.
|
|
pass
|
|
del(tobedone[0])
|
|
else: # no arglist or argdict
|
|
while tobedone:
|
|
object = tobedone[0]
|
|
try:
|
|
alreadydone[id(object)]
|
|
# We've already processed this object
|
|
except KeyError:
|
|
# We haven't processed this object
|
|
alreadydone[id(object)]=1
|
|
function(object)
|
|
try:
|
|
tobedone[1:1]=getattr(object,moreattr)
|
|
except AttributeError:
|
|
# if the object isn't a hierobj, we don't need to recurse into it.
|
|
pass
|
|
del(tobedone[0])
|
|
def hier_rreturn(self, function,arglist=None,argdict={},moreattr = '__childlist__'):
|
|
'''
|
|
Safely apply a function to self and all children,
|
|
collect the results in a list and return.
|
|
|
|
function
|
|
function to apply
|
|
arglist
|
|
(self,)+arglist is the set of arguments passed to function
|
|
argdict
|
|
passed as namedargs to the function
|
|
moreattr
|
|
the attribute representing the children of a node
|
|
'''
|
|
alreadydone = {}
|
|
tobedone = [self]
|
|
results = []
|
|
if arglist or argdict:
|
|
if not arglist: arglist=[self]
|
|
else:
|
|
arglist.insert(0,self) # or anything you feel like
|
|
while tobedone:
|
|
object = tobedone[0]
|
|
try:
|
|
alreadydone[id(object)]
|
|
# We've already processed this object
|
|
except KeyError:
|
|
# We haven't processed this object
|
|
alreadydone[id(object)]=1
|
|
arglist[0]=object
|
|
results.append(apply(function,tuple(arglist),argdict))
|
|
try:
|
|
tobedone[1:1]=getattr(object,moreattr)
|
|
except AttributeError:
|
|
# if the object isn't a hierobj, we don't need to recurse into it.
|
|
pass
|
|
del(tobedone[0])
|
|
else:
|
|
while tobedone:
|
|
object = tobedone[0]
|
|
try:
|
|
alreadydone[id(object)]
|
|
# We've already processed this object
|
|
except KeyError:
|
|
# We haven't processed this object
|
|
alreadydone[id(object)]=1
|
|
results.append(function(object))
|
|
try:
|
|
tobedone[1:1]=getattr(object,moreattr)
|
|
except AttributeError:
|
|
# if the object isn't a hierobj, we don't need to recurse into it.
|
|
pass
|
|
del(tobedone[0])
|
|
return results
|
|
def hier_rgetattr(self, attrname, multiple=1, moreattr = '__childlist__'):
|
|
'''
|
|
Recursively collect the values for attrname and
|
|
return as a list.
|
|
|
|
attrname
|
|
attribute to collect
|
|
arglist
|
|
(self,)+arglist is the set of arguments passed to function
|
|
argdict
|
|
passed as namedargs to the function
|
|
moreattr
|
|
the attribute representing the children of a node
|
|
'''
|
|
alreadydone = {}
|
|
tobedone = [self]
|
|
results = []
|
|
while tobedone:
|
|
object = tobedone[0]
|
|
try:
|
|
alreadydone[id(object)]
|
|
# We've already processed this object
|
|
except KeyError:
|
|
# We haven't processed this object
|
|
alreadydone[id(object)]=1
|
|
try:
|
|
if multiple:
|
|
results.append(getattr(object, attrname))
|
|
else:
|
|
return getattr(object, attrname)
|
|
except AttributeError:
|
|
pass
|
|
try:
|
|
tobedone[1:1]=getattr(object,moreattr)
|
|
except AttributeError:
|
|
# if the object isn't a hierobj, we don't need to recurse into it.
|
|
pass
|
|
del(tobedone[0])
|
|
return results
|
|
def hier_rmethod(self, methodname,arglist=(),argdict={},moreattr = '__childlist__'):
|
|
'''
|
|
return the result of calling every object's method methodname,
|
|
as for hier_rreturn otherwise.
|
|
|
|
methodname
|
|
method to call
|
|
arglist
|
|
(self,)+arglist is the set of arguments passed to function
|
|
argdict
|
|
passed as namedargs to the function
|
|
moreattr
|
|
the attribute representing the children of a node
|
|
'''
|
|
|
|
alreadydone = {}
|
|
tobedone = [self]
|
|
results = []
|
|
while tobedone:
|
|
object = tobedone[0]
|
|
try:
|
|
alreadydone[id(object)]
|
|
# We've already processed this object
|
|
except KeyError:
|
|
# We haven't processed this object
|
|
alreadydone[id(object)]=1
|
|
try:
|
|
results.append(apply(getattr(object,methodname),arglist,argdict))
|
|
except:
|
|
pass
|
|
try:
|
|
tobedone[1:1]=getattr(object,moreattr)
|
|
except AttributeError:
|
|
# if the object isn't a hierobj, we don't need to recurse into it.
|
|
pass
|
|
del(tobedone[0])
|
|
return results
|
|
|