unintuitive for-loop behavior

Jussi Piitulainen jussi.piitulainen at helsinki.fi
Sat Oct 1 10:28:11 EDT 2016


I'm not sure any more to what message this should be a followup, but
here is a demonstration of two different semantics of the for-loop
variable scope/update, this time with nested loops using the same loop
variable name. The first function, tabulate, uses Python semantics ("t"
for true, if you like); the second, fabulate, is a translation ("f" for
false, if you like) that uses the magical semantics where the loop
variable is not only local to the loop but also a different variable on
each iteration. The latter property makes no difference in this
demonstration, but the former does; there's also a spurious counter that
is not local to the nested loops, just to be sure that it works as
expected (it does).

A summary of sorts: it's possible to demonstrate the scope difference in
Python code, with no box in sight; boxes are irrelevant; the relevant
issue is what function and when the loop variable is associated with,
explicitly or implicitly.

def tabulate(m, n):
    for i in range(m):
        print(i, end = ': ')
        c = 0
        for i in range(n):
            print(i, end = ', ' if i + 1 < n else ' : ')
            c += 1
        print(i, c)

def fabulate(m, n):
    c = None # because c belong in this scope
    g1 = iter(range(m))
    try:
        while True:
            def g2(i):
                nonlocal c
                print(i, end = ': ')
                c = 0
                g3 = iter(range(n))
                try:
                    while True:
                        def g4(i):
                            nonlocal c
                            print(i, end = ', ' if i + 1 < n else ' : ')
                            c += 1
                        g4(next(g3))
                except StopIteration:
                    pass
                print(i, c)
            g2(next(g1))
    except StopIteration:
        pass

print('Python:')
tabulate(3, 4)
print()
print('Magick:')
fabulate(3, 4)

# Output from the above, each line being
# outer i: each inner i : i after inner loop, c
# where either c correctly counts inner steps but
# Python inner i clobbers outer i, Magick not.
#
# Python:
# 0: 0, 1, 2, 3 : 3 4
# 1: 0, 1, 2, 3 : 3 4
# 2: 0, 1, 2, 3 : 3 4
#
# Magick:
# 0: 0, 1, 2, 3 : 0 4
# 1: 0, 1, 2, 3 : 1 4
# 2: 0, 1, 2, 3 : 2 4



More information about the Python-list mailing list