Mutating a List Doesn't Need nonlocal, Rebinding Does

def make_tracker():
    log = []
    total = 0
    def record(x):
        log.append(x)
        total += x
        return total
    return record, log

track, log = make_tracker()
track(5)

Now compare with this version, where the only change is one added line inside record:

def make_tracker():
    log = []
    total = 0
    def record(x):
        nonlocal total
        log.append(x)
        total += x
        return total
    return record, log

track, log = make_tracker()
track(5)

What happens in each case?

A

Both versions return 5, since Python resolves total the same way it resolves log

B

Without nonlocal, track(5) raises UnboundLocalError after log already has [5] in it; with nonlocal, track(5) returns 5 and log has [5]

C

Without nonlocal, track(5) raises UnboundLocalError before log is touched, so log stays empty; with nonlocal, track(5) returns 5 and log has [5]

D

Both versions raise UnboundLocalError, because appending to log also requires declaring it nonlocal