This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author josh.r
Recipients Arfrever, aaronwsmith, barry, benjamin.peterson, christian.heimes, eric.snow, ezio.melotti, iritkatriel, josh.r, levkivskyi, ncoghlan, pconnell, pmpp, r.david.murray, serhiy.storchaka
Date 2021-10-01.00:28:43
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1633048123.48.0.675320475641.issue17792@roundup.psfhosted.org>
In-reply-to
Content
Aaron: Your understanding of how LEGB works in Python is a little off.

Locals are locals for the *entire* scope of the function, bound or unbound; deleting them means they hold nothing (they're unbound) but del can't actually stop them from being locals. The choice of whether to look something up in the L, E or GB portions of LEGB scoping rules is a *static* choice made when the function is defined, and is solely about whether they are assigned to anywhere in the function (without an explicit nonlocal/global statement to prevent them becoming locals as a result).

Your second example can be made to fail just by adding a line after the print:

def doSomething():
    print(x)
    x = 1

and it fails for the same reason:

def doSomething():
    x = 10
    del x
    print(x)

fails; a local is a local from entry to exit in a function. Failure to assign to it for a while doesn't change that; it's a local because you assigned to it at least once, along at least one code path. del-ing it after assigning doesn't change that, because del doesn't get rid of locals, it just empties them. Imagine how complex the LOAD_FAST instruction would get if it needed to handle not just loading a local, but when the local wasn't bound, had to choose *dynamically* between:

1. Raising UnboundLocalError (if the value is local, but was never assigned)
2. Returning a closure scoped variable (if the value was local, but got del-ed, and a closure scope exists)
3. Raising NameError (if the closure scope variable exists, but was never assigned)
4. Returning a global/builtin variable (if there was no closure scope variable *or* the closure scope variable was created, but explicitly del-ed)
5. Raising NameError (if no closure, global or builtin name exists)

That's starting to stretch the definition of "fast" in LOAD_FAST. :-)
History
Date User Action Args
2021-10-01 00:28:43josh.rsetrecipients: + josh.r, barry, ncoghlan, christian.heimes, benjamin.peterson, ezio.melotti, Arfrever, r.david.murray, pmpp, eric.snow, serhiy.storchaka, pconnell, levkivskyi, iritkatriel, aaronwsmith
2021-10-01 00:28:43josh.rsetmessageid: <1633048123.48.0.675320475641.issue17792@roundup.psfhosted.org>
2021-10-01 00:28:43josh.rlinkissue17792 messages
2021-10-01 00:28:43josh.rcreate