In the following code, the first reference to iszero succeeds but the second (inside the lambda) gives a NameError: 'iszero' is not defined.
myblock = """
def iszero(x):
return x == 0
print(iszero(0)) #works
args = [0, 1, 2]
flts = list(filter(lambda f:(not iszero(f)), args)) #NameError
"""
mylocals = {}
exec(myblock, globals(), mylocals)
I'd classify this as a Python bug (at very least a documentation bug).
You should open an issue in the Python bug tracker...
The problem is not related to lambda, looks like closures created by exec when a locals dictionary is provided don't have the correct scope resolution.
Curiously enough PyPy has the same behavior, so may be this is indeed the expected result (I can't understand where it's documented, however).
It may seem strange but this is the expected behavior.
The reason is that when exec is provided both a global and local dictionary the code is executed like if it was in the body of a class definition.
That context is quite specific and closures created in it cannot access names defined in the scope of the class (that's why you need to use myclass.myattribute in methods to access class attributes - and that's a lookup that starts from global).
This strange behavior doesn't bite often because normally code at class definition scope just does simple assignments (for class-level attributes) and definitions (for methods) that doesn't try to capture those names.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With