[Tutor] Tutor Digest, Vol 33, Issue 64

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Thu Nov 16 20:51:13 CET 2006


> I have been fighting with this for a couple of days and am getting 
> frustrated with it. I am trying to figure out a way to walk through the 
> windows registry and to capture all nodes under the 
> HKEY_CLASSES_ROOT\CLSID key and then put it into a list.

Ok, let's do this carefully.  Let's first look at the source code, and 
I'll make comments as we go along:


> def ListRegistryKeys(path):
>    # if its empty do nothing
>    if not path: return
>    key=_winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, path)
>    i=0
>    name = []
>    try:
>        while 1:
>            name.append(path + "\\" + _winreg.EnumKey(key, i))
>            print name[-1]
>            i += 1
>    except WindowsError:
>        pass
>    _winreg.CloseKey( key)
>    for item in name:
>        ListRegistryKeys(item)
>    return name

First, we have to say what ListRegisterKeys expects to take in and what we 
expect for it to return.  Here, it looks like it expects to take in a 
path, and returns...?  It looks like it's supposed to return a list of 
names.


If that's true, take a very close look at any place where ListRegistryKeys 
is being used, or where it is returning values back:

>    # if its empty do nothing
>    if not path: return

That's not quite right: it must return some list of things.  Thankfully, 
it's perfectly ok to return a list of no elements:

     if not path: return []


Ok, let's look at another snippet:

>    for item in name:
>        ListRegistryKeys(item)

What's going on here are recursive calls.  From the reasoning above, we 
know that ListRegistryKeys() will give us back a list of names for that 
item.  We'd better not let those results just drop onto the floor.  We 
should collect them!

     subnames = []
     for item in name:
         subnames.extend(ListRegistryKeys(item))

We collect all of the names of the inner registry keys in 'subnames'.

Finally, when we return the result of the whole thing, we must combine the 
results of the recursive calls together with our initial set of names.

     return name + subnames


Here's what the code looks like with all those changes, plus some variable 
renaming and variable shifting.

##############################################################
def ListRegistryKeys(path):
     """ListRegistryKeys: given a path, returns a list of key names
     underneath that path."""
     if not path:
         return []
     names = []
     key = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, path)
     try:
         i = 0
         while 1:
             names.append(path + "\\" + _winreg.EnumKey(key, i))
             i += 1
     except WindowsError:
         pass
     _winreg.CloseKey(key)
     subnames = []
     for item in names:
         subnames.extend(ListRegistryKeys(item))
     return names + subnames
##############################################################


You may want to read:

     http://www.ibiblio.org/obp/thinkCSpy/chap04.html#auto8

... Unfortunately, the way that that book introduces recursive functions 
is bad in the sense that it focuses way too much on IO, on printing things 
rather than on manipulating values.

The meager example in the next chapter is not much better.

     http://www.ibiblio.org/obp/thinkCSpy/chap05.html#auto4

Ugh.  The factorial function is a sad way to introduce recursion because 
it's irrelevant to most people.


If you have time, take a look at:

     http://www.htdp.org/

In particular,

     http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-13.html#node_sec_9.4

which isn't Python, but has a good approach to teaching useful recursion. 
You can then bring that knowledge back into Python-space.


More information about the Tutor mailing list