Issue 6921: recursion wierdness ... related to variable scoping? (original) (raw)

I was playing about with ideas behind b-plus-trees and found i python bug

the important bit of code is:

        for p, k in enumerate(self.keys):
            self.ptrs[p].dump(indent+1, kmin=lk, kmax=k)
            print sindent + "(" + str(k) + ")"
            lk = k

        #
        # python bug?
        #
        show_python_bug = len(sys.argv)>1
        if show_python_bug:
            #
            # why not this?
            assert p == len(self.keys)-1
        else:
            #
            # why do I need this instead?
            p = len(self.keys)-1

i'm expecting k to still be in scope and equal len(self.keys)-1 sometimes it is and sometimes it isn't (depending on recursion depth)

you can try it for yourselves as I attach the full program:

./btree.py runs fine ./btree.py show_python_bug eventually breaks like this:

Traceback (most recent call last): File "./btree.py", line 235, in page.dump() File "./btree.py", line 223, in dump self.ptrs[p+1].dump(indent+1, kmin=lk) File "./btree.py", line 223, in dump self.ptrs[p+1].dump(indent+1, kmin=lk) File "./btree.py", line 223, in dump self.ptrs[p+1].dump(indent+1, kmin=lk) File "./btree.py", line 217, in dump assert p == len(self.keys)-1 UnboundLocalError: local variable 'p' referenced before assignment

... despite executing that code many times successfully before this happens ... strange!

I hope you can figure it out and that this report proves helpful.

This is almost certainly not a bug in Python. At a guess, in the outermost 'else' clause of your dump method, self.keys can be empty. Then the 'for p, k in enumerate(self.keys):' does zero iterations, so p is not defined in the assert; hence the error message.

If you want help figuring out exactly what's going wrong, I'd suggest asking on comp.lang.python.

Ah, I see the problem now: you're expecting that after

for p, elt in enumerate(mylist):

p will be equal to len(mylist)-1. That's true if mylist is nonempty (because on the last round of the for loop, p gets the value len(mylist)- 1), but if mylist is empty then no assignment to p or to elt is ever made.
That's just the way that Python for loops work, I'm afraid. :-)